diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51298b2..b407b58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,8 +47,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - #test-name: [api, directory, directory_hca, tuple] - test-name: [api] + test-name: [api, directory, directory_hca, tuple] api-version: [710] container: image: ghcr.io/emqx/couchdb-erlfdb:erlang-25-fdb-7.1.43 diff --git a/c_src/main.c b/c_src/main.c index 9725b9c..6dc7a5c 100644 --- a/c_src/main.c +++ b/c_src/main.c @@ -199,6 +199,34 @@ erlfdb_future_get_int64(ErlNifEnv* env, ErlFDBFuture* f) return enif_make_int64(env, nif_res); } +static inline ERL_NIF_TERM +erlfdb_future_get_key_array(ErlNifEnv* env, ErlFDBFuture* f) +{ + const FDBKey* keys; + int count; + unsigned char* buf; + ERL_NIF_TERM bin; + ERL_NIF_TERM ret; + fdb_error_t err; + int i; + + err = fdb_future_get_key_array(f->future, &keys, &count); + if(err != 0) { + return erlfdb_erlang_error(env, err); + } + + ret = enif_make_list(env, 0); + + for(i = count - 1; i >= 0; i--) { + const FDBKey key = keys[i]; + buf = enif_make_new_binary(env, key.key_length, &bin); + memcpy(buf, key.key, key.key_length); + ret = enif_make_list_cell(env, bin, ret); + } + + return ret; +} + static inline ERL_NIF_TERM erlfdb_future_get_key(ErlNifEnv* env, ErlFDBFuture* f) @@ -660,6 +688,8 @@ erlfdb_future_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return erlfdb_future_get_string_array(env, f); } else if(f->ftype == ErlFDB_FT_KEYVALUE_ARRAY) { return erlfdb_future_get_keyvalue_array(env, f); + } else if(f->ftype == ErlFDB_FT_KEY_ARRAY) { + return erlfdb_future_get_key_array(env, f); } return enif_raise_exception(env, ATOM_invalid_future_type); @@ -1139,6 +1169,62 @@ erlfdb_transaction_get_estimated_range_size( } #endif +static ERL_NIF_TERM +erlfdb_transaction_get_range_split_points( + ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[] + ) +{ + ErlFDBSt* st = (ErlFDBSt*) enif_priv_data(env); + ErlFDBTransaction* t; + ErlNifBinary begin; + ErlNifBinary end; + int64_t chunkSize; + FDBFuture* future; + void* res; + + if(st->lib_state != ErlFDB_CONNECTED) { + return enif_make_badarg(env); + } + + if(argc != 4) { + return enif_make_badarg(env); + } + + if(!enif_get_resource(env, argv[0], ErlFDBTransactionRes, &res)) { + return enif_make_badarg(env); + } + t = (ErlFDBTransaction*) res; + + if(!erlfdb_transaction_is_owner(env, t)) { + return enif_make_badarg(env); + } + + if(!enif_inspect_binary(env, argv[1], &begin)) { + return enif_make_badarg(env); + } + + if(!enif_inspect_binary(env, argv[2], &end)) { + return enif_make_badarg(env); + } + + if(!enif_get_int64(env, argv[3], &chunkSize)) { + return enif_make_badarg(env); + } + + future = fdb_transaction_get_range_split_points( + t->transaction, + (uint8_t*) begin.data, + begin.size, + (uint8_t*) end.data, + end.size, + chunkSize + ); + + return erlfdb_create_future(env, future, ErlFDB_FT_KEY_ARRAY); +} + static ERL_NIF_TERM erlfdb_transaction_get_key( ErlNifEnv* env, @@ -2210,6 +2296,7 @@ static ErlNifFunc funcs[] = NIF_FUNC(erlfdb_transaction_set_read_version, 2), NIF_FUNC(erlfdb_transaction_get_read_version, 1), NIF_FUNC(erlfdb_transaction_get, 3), + NIF_FUNC(erlfdb_transaction_get_range_split_points, 4), NIF_FUNC(erlfdb_transaction_get_key, 3), NIF_FUNC(erlfdb_transaction_get_addresses_for_key, 2), NIF_FUNC(erlfdb_transaction_get_range, 9), diff --git a/c_src/resources.h b/c_src/resources.h index b25a43f..15ffd51 100644 --- a/c_src/resources.h +++ b/c_src/resources.h @@ -32,7 +32,8 @@ typedef enum _ErlFDBFutureType ErlFDB_FT_KEY, ErlFDB_FT_VALUE, ErlFDB_FT_STRING_ARRAY, - ErlFDB_FT_KEYVALUE_ARRAY + ErlFDB_FT_KEYVALUE_ARRAY, + ErlFDB_FT_KEY_ARRAY } ErlFDBFutureType; diff --git a/src/erlfdb.erl b/src/erlfdb.erl index 7c26750..1bc2e36 100644 --- a/src/erlfdb.erl +++ b/src/erlfdb.erl @@ -48,6 +48,8 @@ get/2, get_ss/2, + get_range_split_points/4, + get_key/2, get_key_ss/2, @@ -296,6 +298,13 @@ get_ss(?IS_TX = Tx, Key) -> get_ss(?IS_SS = SS, Key) -> get_ss(?GET_TX(SS), Key). +get_range_split_points(?IS_DB = Db, BeginKey, EndKey, ChunkSize) -> + transactional(Db, fun(Tx) -> + wait(get_range_split_points(Tx, BeginKey, EndKey, ChunkSize)) + end); +get_range_split_points(?IS_TX = Tx, BeginKey, EndKey, ChunkSize) -> + erlfdb_nif:transaction_get_range_split_points(Tx, BeginKey, EndKey, ChunkSize). + get_key(?IS_DB = Db, Key) -> transactional(Db, fun(Tx) -> wait(get_key(Tx, Key)) diff --git a/src/erlfdb_nif.erl b/src/erlfdb_nif.erl index 1c2568f..a429370 100644 --- a/src/erlfdb_nif.erl +++ b/src/erlfdb_nif.erl @@ -37,6 +37,7 @@ transaction_get_read_version/1, transaction_get/3, transaction_get_estimated_range_size/3, + transaction_get_range_split_points/4, transaction_get_key/3, transaction_get_addresses_for_key/2, transaction_get_range/9, @@ -284,6 +285,11 @@ transaction_get({erlfdb_transaction, Tx}, Key, Snapshot) -> transaction_get_estimated_range_size({erlfdb_transaction, Tx}, StartKey, EndKey) -> erlfdb_transaction_get_estimated_range_size(Tx, StartKey, EndKey). +-spec transaction_get_range_split_points(transaction(), BeginKey :: binary(), EndKey :: binary(), ChunkSize :: non_neg_integer()) -> + future(). +transaction_get_range_split_points({erlfdb_transaction, Tx}, BeginKey, EndKey, ChunkSize) -> + erlfdb_transaction_get_range_split_points(Tx, BeginKey, EndKey, ChunkSize). + -spec transaction_get_key( transaction(), KeySelector :: key_selector(), @@ -531,6 +537,8 @@ erlfdb_transaction_set_read_version(_Transaction, _Version) -> ?NOT_LOADED. erlfdb_transaction_get_read_version(_Transaction) -> ?NOT_LOADED. erlfdb_transaction_get(_Transaction, _Key, _Snapshot) -> ?NOT_LOADED. erlfdb_transaction_get_estimated_range_size(_Transaction, _SKey, _EKey) -> ?NOT_LOADED. +erlfdb_transaction_get_range_split_points(_Transaction, _BeginKey, _EndKey, _ChunkSize) -> + ?NOT_LOADED. erlfdb_transaction_get_key(_Transaction, _KeySelector, _Snapshot) -> ?NOT_LOADED. erlfdb_transaction_get_addresses_for_key(_Transaction, _Key) -> ?NOT_LOADED. erlfdb_transaction_get_range( diff --git a/test/tester.es b/test/tester.es index 617c03d..3e9e8af 100755 --- a/test/tester.es +++ b/test/tester.es @@ -779,6 +779,12 @@ execute(TxObj, #st{is_directory_op = true} = St, Op) -> NewSt end; +execute(TxObj, St, <<"GET_RANGE_SPLIT_POINTS">>) -> + [Start, End, ChunkSize] = stack_pop(St, 3), + Result = erlfdb:get_range_split_points(TxObj, Start, End, ChunkSize), + stack_push_range(St, Result), + St; + execute(_TxObj, _St, UnknownOp) -> erlang:error({unknown_op, UnknownOp}).