Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/backup #10

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ c_src/snappy*/
c_src/system
*~
.rebar
backup.db
test.db
4 changes: 3 additions & 1 deletion c_src/atoms.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ extern ERL_NIF_TERM ATOM_DISABLE_WAL;
extern ERL_NIF_TERM ATOM_TIMEOUT_HINT_US;
extern ERL_NIF_TERM ATOM_IGNORE_MISSING_COLUMN_FAMILIES;

// Related to Write Actions
// Related to Write Actions
extern ERL_NIF_TERM ATOM_CLEAR;
extern ERL_NIF_TERM ATOM_PUT;
extern ERL_NIF_TERM ATOM_DELETE;
Expand Down Expand Up @@ -157,6 +157,8 @@ extern ERL_NIF_TERM ATOM_ERROR_DB_DELETE;
extern ERL_NIF_TERM ATOM_ERROR_DB_WRITE;
extern ERL_NIF_TERM ATOM_ERROR_DB_DESTROY;
extern ERL_NIF_TERM ATOM_ERROR_DB_REPAIR;
extern ERL_NIF_TERM ATOM_ERROR_DB_BACKUP;
extern ERL_NIF_TERM ATOM_ERROR_DB_RESTORE;
extern ERL_NIF_TERM ATOM_BAD_WRITE_ACTION;
extern ERL_NIF_TERM ATOM_KEEP_RESOURCE_FAILED;
extern ERL_NIF_TERM ATOM_ITERATOR_CLOSED;
Expand Down
2 changes: 1 addition & 1 deletion c_src/build_deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
fi
unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well

ROCKSDB_VSN="rocksdb-3.11.2"
ROCKSDB_VSN="rocksdb-4.1"

SNAPPY_VSN="1.1.1"

Expand Down
115 changes: 111 additions & 4 deletions c_src/erocksdb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "rocksdb/table.h"
#include "rocksdb/filter_policy.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/utilities/backupable_db.h"

#ifndef INCL_THREADING_H
#include "threading.h"
Expand All @@ -67,6 +68,8 @@ static ErlNifFunc nif_funcs[] =
{"destroy", 2, erocksdb_destroy},
{"repair", 2, erocksdb_repair},
{"is_empty", 1, erocksdb_is_empty},
{"backup", 2, erocksdb_backup},
{"restore", 2, erocksdb_restore},

{"async_open", 4, erocksdb::async_open},
{"async_write", 4, erocksdb::async_write},
Expand Down Expand Up @@ -172,7 +175,7 @@ ERL_NIF_TERM ATOM_DISABLE_WAL;
ERL_NIF_TERM ATOM_TIMEOUT_HINT_US;
ERL_NIF_TERM ATOM_IGNORE_MISSING_COLUMN_FAMILIES;

// Related to Write Actions
// Related to Write Actions
ERL_NIF_TERM ATOM_CLEAR;
ERL_NIF_TERM ATOM_PUT;
ERL_NIF_TERM ATOM_DELETE;
Expand Down Expand Up @@ -217,6 +220,8 @@ ERL_NIF_TERM ATOM_BAD_WRITE_ACTION;
ERL_NIF_TERM ATOM_KEEP_RESOURCE_FAILED;
ERL_NIF_TERM ATOM_ITERATOR_CLOSED;
ERL_NIF_TERM ATOM_INVALID_ITERATOR;
ERL_NIF_TERM ATOM_ERROR_DB_BACKUP;
ERL_NIF_TERM ATOM_ERROR_DB_RESTORE;

// Related to NIF initialize parameters
ERL_NIF_TERM ATOM_WRITE_THREADS;
Expand Down Expand Up @@ -362,7 +367,7 @@ ERL_NIF_TERM parse_db_option(ErlNifEnv* env, ERL_NIF_TERM item, rocksdb::Options
ERL_NIF_TERM tail;
char db_name[4096];
while(enif_get_list_cell(env, option[1], &head, &tail)) {
if (enif_get_string(env, head, db_name, sizeof(db_name), ERL_NIF_LATIN1))
if (enif_get_string(env, head, db_name, sizeof(db_name), ERL_NIF_LATIN1))
{
std::string str_db_name(db_name);
rocksdb::DbPath db_path(str_db_name, 0);
Expand Down Expand Up @@ -515,7 +520,7 @@ ERL_NIF_TERM parse_cf_option(ErlNifEnv* env, ERL_NIF_TERM item, rocksdb::Options
if (enif_get_tuple(env, item, &arity, &option) && 2==arity)
{
if (option[0] == erocksdb::ATOM_BLOCK_CACHE_SIZE_MB_FOR_POINT_LOOKUP)
// @TODO ignored now
// @TODO ignored now
;
else if (option[0] == erocksdb::ATOM_MEMTABLE_MEMORY_BUDGET)
{
Expand Down Expand Up @@ -741,7 +746,7 @@ ERL_NIF_TERM parse_cf_option(ErlNifEnv* env, ERL_NIF_TERM item, rocksdb::Options
}
return erocksdb::ATOM_OK;
}

ERL_NIF_TERM parse_read_option(ErlNifEnv* env, ERL_NIF_TERM item, rocksdb::ReadOptions& opts)
{
int arity;
Expand Down Expand Up @@ -1186,6 +1191,7 @@ async_iterator_move(
} // namespace erocksdb



/***
* HEY YOU, please convert this to an async operation
*/
Expand Down Expand Up @@ -1402,6 +1408,104 @@ erocksdb_is_empty(
} // erocksdb_is_empty


ERL_NIF_TERM
erocksdb_backup(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{

erocksdb::DbObject * db_ptr;
ERL_NIF_TERM ret_term;

db_ptr=erocksdb::DbObject::RetrieveDbObject(env, argv[0]);

char backup_path[4096];

if(!enif_get_string(env, argv[1], backup_path, sizeof(backup_path), ERL_NIF_LATIN1))
{
return enif_make_badarg(env);
}

if (NULL!=db_ptr)
{
rocksdb::BackupEngine* backup_engine;
rocksdb::Status s = rocksdb::BackupEngine::Open(rocksdb::Env::Default(),
rocksdb::BackupableDBOptions(backup_path), &backup_engine);

if(!s.ok())
{
return error_tuple(env, erocksdb::ATOM_ERROR_DB_BACKUP, s);
}


rocksdb::Status status = backup_engine->CreateNewBackup(db_ptr->m_Db);
if(!status.ok())
{
ret_term = error_tuple(env, erocksdb::ATOM_ERROR_DB_BACKUP, status);
}
else
{
ret_term=erocksdb::ATOM_OK;
}
delete backup_engine;
}
else
{
ret_term=enif_make_badarg(env);
}

return(ret_term);
} // erocksdb_backup


ERL_NIF_TERM
erocksdb_restore(
ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{

ERL_NIF_TERM ret_term;

char db_path[4096];
char backup_path[4096];

if(!enif_get_string(env, argv[0], backup_path, sizeof(backup_path), ERL_NIF_LATIN1))
{
return enif_make_badarg(env);
}

if(!enif_get_string(env, argv[1], db_path, sizeof(db_path), ERL_NIF_LATIN1))
{
return enif_make_badarg(env);
}


rocksdb::BackupEngineReadOnly* backup_engine;
rocksdb::Status s = rocksdb::BackupEngineReadOnly::Open(rocksdb::Env::Default(),
rocksdb::BackupableDBOptions(backup_path), &backup_engine);

if(!s.ok())
{
return error_tuple(env, erocksdb::ATOM_ERROR_DB_BACKUP, s);
}

rocksdb::Status status = backup_engine->RestoreDBFromLatestBackup(db_path, db_path);
delete backup_engine;

if(!status.ok())
{
ret_term = error_tuple(env, erocksdb::ATOM_ERROR_DB_RESTORE, status);
}
else
{
ret_term=erocksdb::ATOM_OK;
}
return(ret_term);
} // erocksdb_restore


static void on_unload(ErlNifEnv *env, void *priv_data)
{
erocksdb_priv_data *p = static_cast<erocksdb_priv_data *>(priv_data);
Expand Down Expand Up @@ -1558,6 +1662,9 @@ try
ATOM(erocksdb::ATOM_KEEP_RESOURCE_FAILED, "keep_resource_failed");
ATOM(erocksdb::ATOM_ITERATOR_CLOSED, "iterator_closed");
ATOM(erocksdb::ATOM_INVALID_ITERATOR, "invalid_iterator");
ATOM(erocksdb::ATOM_ERROR_DB_BACKUP, "error_db_backup");
ATOM(erocksdb::ATOM_ERROR_DB_RESTORE, "error_db_restore");


// Related to NIF initialize parameters
ATOM(erocksdb::ATOM_WRITE_THREADS, "write_threads");
Expand Down
2 changes: 2 additions & 0 deletions c_src/erocksdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ ERL_NIF_TERM erocksdb_status(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM erocksdb_destroy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM erocksdb_repair(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM erocksdb_is_empty(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM erocksdb_backup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM erocksdb_restore(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
}

namespace erocksdb {
Expand Down
13 changes: 13 additions & 0 deletions src/erocksdb.erl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
-export([iterator/2, iterator/3, iterator_with_cf/3, iterator_move/2, iterator_close/1]).
-export([fold/4, fold/5, fold_keys/4, fold_keys/5]).
-export([destroy/2, repair/2, is_empty/1]).
-export([backup/2, restore/2]).
-export([count/1, count/2, status/1, status/2, status/3]).

-export_type([db_handle/0,
Expand Down Expand Up @@ -456,6 +457,18 @@ destroy(_Name, _DBOpts) ->
repair(_Name, _DBOpts) ->
erlang:nif_error({error, not_loaded}).

%% @doc backup a database
-spec backup(DbHandle::db_handle(), BackupPath::file:filename_all())
-> ok | {error, error_db_backup}.
backup(_DbHandle, _BackupPath) ->
erlang:nif_error({error, not_loaded}).

%% @doc restore a database from last backup
-spec restore(BackupPath::file:filename_all(), DbPath::file:filename_all())
-> ok | {error, error_db_restore}.
restore(_BackupPath, _DbPath) ->
erlang:nif_error({error, not_loaded}).

%% @doc
%% Return the approximate number of keys in the default column family.
%% Implemented by calling GetIntProperty with "rocksdb.estimate-num-keys"
Expand Down
54 changes: 54 additions & 0 deletions test/backup_test.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2016 Benoît Chesneau.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(backup_test).
-compile([export_all/1]).
-include_lib("eunit/include/eunit.hrl").

backup_test() ->
os:cmd("rm -rf test.db"),
os:cmd("rm -rf test_backup.db"),

{ok, Ref} = erocksdb:open("test.db", [{create_if_missing, true}], []),
try
erocksdb:put(Ref, <<"a">>, <<"x">>, []),
?assertEqual({ok, <<"x">>}, erocksdb:get(Ref, <<"a">>, [])),
ok = erocksdb:backup(Ref, "test_backup.db"),
?assert(filelib:is_dir("test_backup.db")),
erocksdb:put(Ref, <<"a">>, <<"y">>, []),
?assertEqual({ok, <<"y">>}, erocksdb:get(Ref, <<"a">>, []))
after
erocksdb:close(Ref)
end,
ok = erocksdb:restore("test_backup.db", "test.db"),
{ok, Ref2} = erocksdb:open("test.db", [], []),
try
?assertEqual({ok, <<"x">>}, erocksdb:get(Ref2, <<"a">>, []))
after
erocksdb:close(Ref2)
end.