From c2c1ba0699b72d2f9e111bf8945e1bdc3682ef68 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Fri, 2 Feb 2024 16:16:24 -0500 Subject: [PATCH 1/6] Adds FDB Tenants --- c_src/atom_names.h | 2 + c_src/fdb.h | 5 +- c_src/main.c | 104 +++++++++++++++++++++++++ c_src/resources.c | 24 ++++++ c_src/resources.h | 6 ++ src/erlfdb.app.src | 2 +- src/erlfdb.erl | 15 ++++ src/erlfdb_nif.erl | 27 ++++++- src/erlfdb_tenant_management.erl | 54 +++++++++++++ src/erlfdb_util.erl | 62 ++++++++++++--- test/erlfdb_02_anon_fdbserver_test.erl | 48 +++++++----- 11 files changed, 317 insertions(+), 32 deletions(-) create mode 100644 src/erlfdb_tenant_management.erl diff --git a/c_src/atom_names.h b/c_src/atom_names.h index 1e524b3..acb132c 100644 --- a/c_src/atom_names.h +++ b/c_src/atom_names.h @@ -29,6 +29,7 @@ ATOM_MAP(not_found); ATOM_MAP(erlfdb_error); ATOM_MAP(erlfdb_future); ATOM_MAP(erlfdb_database); +ATOM_MAP(erlfdb_tenant); ATOM_MAP(erlfdb_transaction); ATOM_MAP(invalid_future_type); @@ -109,6 +110,7 @@ ATOM_MAP(disallow_writes); ATOM_MAP(include_port_in_address); ATOM_MAP(use_provisional_proxies); ATOM_MAP(report_conflicting_keys); +ATOM_MAP(special_key_space_enable_writes); // Streaming mode diff --git a/c_src/fdb.h b/c_src/fdb.h index ae7f616..c8a1555 100644 --- a/c_src/fdb.h +++ b/c_src/fdb.h @@ -13,8 +13,11 @@ #ifndef ERLFDB_FDB_H #define ERLFDB_FDB_H +// FDB_LATEST_API_VERSION +#include + #ifndef FDB_API_VERSION -#define FDB_API_VERSION 620 +#define FDB_API_VERSION FDB_LATEST_API_VERSION #endif // Allow command-line override of default FDB_API_VERSION #include diff --git a/c_src/main.c b/c_src/main.c index 8cb03b0..a2d48d2 100644 --- a/c_src/main.c +++ b/c_src/main.c @@ -765,6 +765,54 @@ erlfdb_create_database(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } +static ERL_NIF_TERM +erlfdb_database_open_tenant(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlFDBSt* st = (ErlFDBSt*) enif_priv_data(env); + ErlNifBinary bin; + ErlFDBDatabase* d; + ErlFDBTenant* ten; + FDBTenant* tenant; + fdb_error_t err; + ERL_NIF_TERM ret; + void* res; + + if(st->lib_state != ErlFDB_CONNECTED) { + return enif_make_badarg(env); + } + + if(argc != 2) { + return enif_make_badarg(env); + } + + if(!enif_get_resource(env, argv[0], ErlFDBDatabaseRes, &res)) { + return enif_make_badarg(env); + } + d = (ErlFDBDatabase*) res; + + if(!enif_inspect_binary(env, argv[1], &bin)) { + return enif_make_badarg(env); + } + + if(bin.size < 1 || bin.data[bin.size - 1] != 0) { + return enif_make_badarg(env); + } + + err = fdb_database_open_tenant(d->database, (const unsigned char*) bin.data, bin.size-1, &tenant); + if(err != 0) { + return erlfdb_erlang_error(env, err); + } + + ten = enif_alloc_resource(ErlFDBTenantRes, sizeof(ErlFDBTenant)); + ten->tenant = tenant; + + ret = enif_make_resource(env, ten); + enif_release_resource(ten); + + return T2(env, ATOM_erlfdb_tenant, ret); +} + + static ERL_NIF_TERM erlfdb_database_set_option(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { @@ -887,6 +935,56 @@ erlfdb_database_create_transaction( return T2(env, ATOM_erlfdb_transaction, ret); } +static ERL_NIF_TERM +erlfdb_tenant_create_transaction( + ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[] + ) +{ + ErlFDBSt* st = (ErlFDBSt*) enif_priv_data(env); + ErlFDBTenant* ten; + ErlFDBTransaction* t; + FDBTransaction* transaction; + ErlNifPid pid; + ERL_NIF_TERM ret; + void* res; + fdb_error_t err; + + if(st->lib_state != ErlFDB_CONNECTED) { + return enif_make_badarg(env); + } + + if(argc != 1) { + return enif_make_badarg(env); + } + + if(!enif_get_resource(env, argv[0], ErlFDBTenantRes, &res)) { + return enif_make_badarg(env); + } + ten = (ErlFDBTenant*) res; + + err = fdb_tenant_create_transaction(ten->tenant, &transaction); + if(err != 0) { + return erlfdb_erlang_error(env, err); + } + + t = enif_alloc_resource(ErlFDBTransactionRes, sizeof(ErlFDBTransaction)); + t->transaction = transaction; + + enif_self(env, &pid); + t->owner = enif_make_pid(env, &pid); + + t->txid = 0; + t->read_only = true; + t->writes_allowed = true; + t->has_watches = false; + + ret = enif_make_resource(env, t); + enif_release_resource(t); + return T2(env, ATOM_erlfdb_transaction, ret); +} + static ERL_NIF_TERM erlfdb_transaction_set_option( @@ -994,6 +1092,10 @@ erlfdb_transaction_set_option( #if FDB_API_VERSION > 620 } else if(IS_ATOM(argv[1], report_conflicting_keys)) { option = FDB_TR_OPTION_REPORT_CONFLICTING_KEYS; +#endif +#if FDB_API_VERSION > 630 + } else if(IS_ATOM(argv[1], special_key_space_enable_writes)) { + option = FDB_TR_OPTION_SPECIAL_KEY_SPACE_ENABLE_WRITES; #endif } else { return enif_make_badarg(env); @@ -2261,7 +2363,9 @@ static ErlNifFunc funcs[] = NIF_FUNC(erlfdb_create_database, 1), NIF_FUNC(erlfdb_database_set_option, 3), + NIF_FUNC(erlfdb_database_open_tenant, 2), NIF_FUNC(erlfdb_database_create_transaction, 1), + NIF_FUNC(erlfdb_tenant_create_transaction, 1), NIF_FUNC(erlfdb_transaction_set_option, 3), NIF_FUNC(erlfdb_transaction_set_read_version, 2), diff --git a/c_src/resources.c b/c_src/resources.c index 9be74af..17d3efb 100644 --- a/c_src/resources.c +++ b/c_src/resources.c @@ -15,6 +15,7 @@ ErlNifResourceType* ErlFDBFutureRes; ErlNifResourceType* ErlFDBDatabaseRes; +ErlNifResourceType* ErlFDBTenantRes; ErlNifResourceType* ErlFDBTransactionRes; @@ -46,6 +47,18 @@ erlfdb_init_resources(ErlNifEnv* env) return 0; } + ErlFDBTenantRes = enif_open_resource_type( + env, + NULL, + "erlfdb_tenant", + erlfdb_tenant_dtor, + ERL_NIF_RT_CREATE, + NULL + ); + if(ErlFDBTenantRes == NULL) { + return 0; + } + ErlFDBTransactionRes = enif_open_resource_type( env, NULL, @@ -92,6 +105,17 @@ erlfdb_database_dtor(ErlNifEnv* env, void* obj) } +void +erlfdb_tenant_dtor(ErlNifEnv* env, void* obj) +{ + ErlFDBTenant* ten = (ErlFDBTenant*) obj; + + if(ten->tenant != NULL) { + fdb_tenant_destroy(ten->tenant); + } +} + + void erlfdb_transaction_dtor(ErlNifEnv* env, void* obj) { diff --git a/c_src/resources.h b/c_src/resources.h index b25a43f..3ff5c78 100644 --- a/c_src/resources.h +++ b/c_src/resources.h @@ -21,6 +21,7 @@ extern ErlNifResourceType* ErlFDBFutureRes; extern ErlNifResourceType* ErlFDBDatabaseRes; +extern ErlNifResourceType* ErlFDBTenantRes; extern ErlNifResourceType* ErlFDBTransactionRes; @@ -54,6 +55,10 @@ typedef struct _ErlFDBDatabase FDBDatabase* database; } ErlFDBDatabase; +typedef struct _ErlFDBTenant +{ + FDBTenant* tenant; +} ErlFDBTenant; typedef struct _ErlFDBTransaction { @@ -69,6 +74,7 @@ typedef struct _ErlFDBTransaction int erlfdb_init_resources(ErlNifEnv* env); void erlfdb_future_dtor(ErlNifEnv* env, void* obj); void erlfdb_database_dtor(ErlNifEnv* env, void* obj); +void erlfdb_tenant_dtor(ErlNifEnv* env, void* obj); void erlfdb_transaction_dtor(ErlNifEnv* env, void* obj); diff --git a/src/erlfdb.app.src b/src/erlfdb.app.src index 5ebf210..fc8c066 100644 --- a/src/erlfdb.app.src +++ b/src/erlfdb.app.src @@ -18,7 +18,7 @@ {maintainers, ["Paul J. Davis"]}, {links, [{"GitHub", "https://github.com/cloudant-labs/couchdb-erlfdb"}]}, {env, [ - {api_version, 620}, + {api_version, 730}, {network_options, []} ]} ]}. diff --git a/src/erlfdb.erl b/src/erlfdb.erl index 7c26750..4e39223 100644 --- a/src/erlfdb.erl +++ b/src/erlfdb.erl @@ -18,7 +18,11 @@ open/0, open/1, + open_tenant/2, + create_transaction/1, + tenant_create_transaction/1, + transactional/2, snapshot/1, @@ -127,6 +131,7 @@ -define(IS_FUTURE, {erlfdb_future, _, _}). -define(IS_FOLD_FUTURE, {fold_info, _, _}). -define(IS_DB, {erlfdb_database, _}). +-define(IS_TENANT, {erlfdb_tenant, _}). -define(IS_TX, {erlfdb_transaction, _}). -define(IS_SS, {erlfdb_snapshot, _}). -define(GET_TX(SS), element(2, SS)). @@ -149,13 +154,23 @@ open() -> open(ClusterFile) -> erlfdb_nif:create_database(ClusterFile). +open_tenant(?IS_DB = Db, TenantName) -> + erlfdb_nif:database_open_tenant(Db, TenantName). + create_transaction(?IS_DB = Db) -> erlfdb_nif:database_create_transaction(Db). +tenant_create_transaction(?IS_TENANT = Tenant) -> + erlfdb_nif:tenant_create_transaction(Tenant). + transactional(?IS_DB = Db, UserFun) when is_function(UserFun, 1) -> clear_erlfdb_error(), Tx = create_transaction(Db), do_transaction(Tx, UserFun); +transactional(?IS_TENANT = Tenant, UserFun) when is_function(UserFun, 1) -> + clear_erlfdb_error(), + Tx = tenant_create_transaction(Tenant), + do_transaction(Tx, UserFun); transactional(?IS_TX = Tx, UserFun) when is_function(UserFun, 1) -> UserFun(Tx); transactional(?IS_SS = SS, UserFun) when is_function(UserFun, 1) -> diff --git a/src/erlfdb_nif.erl b/src/erlfdb_nif.erl index 4e70303..b3546c5 100644 --- a/src/erlfdb_nif.erl +++ b/src/erlfdb_nif.erl @@ -27,9 +27,11 @@ future_get/1, create_database/1, + database_open_tenant/2, database_set_option/2, database_set_option/3, database_create_transaction/1, + tenant_create_transaction/1, transaction_set_option/2, transaction_set_option/3, @@ -62,11 +64,12 @@ error_predicate/2 ]). --define(DEFAULT_API_VERSION, 620). +-define(DEFAULT_API_VERSION, 730). -type error() :: {erlfdb_error, Code :: integer()}. -type future() :: {erlfdb_future, reference(), reference()}. -type database() :: {erlfdb_database, reference()}. +-type tenant() :: {erlfdb_tenant, reference()}. -type transaction() :: {erlfdb_transaction, reference()}. -type option_value() :: integer() | binary(). @@ -224,6 +227,22 @@ create_database(ClusterFilePath) -> end, erlfdb_create_database(NifPath). +-spec database_open_tenant(database(), TenantName :: binary()) -> database(). +database_open_tenant(Database, <<>>) -> + database_open_tenant(Database, <<0>>); +database_open_tenant({erlfdb_database, Database}, TenantName) -> + Size = size(TenantName) - 1, + % Make sure we pass a NULL-terminated string + % to FoundationDB + NifTenant = + case TenantName of + <<_:Size/binary, 0>> -> + TenantName; + _ -> + <> + end, + erlfdb_database_open_tenant(Database, NifTenant). + -spec database_set_option(database(), Option :: database_option()) -> ok. database_set_option(Database, Option) -> database_set_option(Database, Option, <<>>). @@ -241,6 +260,10 @@ database_set_option({erlfdb_database, Db}, Opt, Val) -> database_create_transaction({erlfdb_database, Db}) -> erlfdb_database_create_transaction(Db). +-spec tenant_create_transaction(tenant()) -> transaction(). +tenant_create_transaction({erlfdb_tenant, T}) -> + erlfdb_tenant_create_transaction(T). + -spec transaction_set_option(transaction(), Option :: transaction_option()) -> ok. transaction_set_option(Transaction, Option) -> transaction_set_option(Transaction, Option, <<>>). @@ -512,8 +535,10 @@ erlfdb_future_get(_Future) -> ?NOT_LOADED. % Databases erlfdb_create_database(_ClusterFilePath) -> ?NOT_LOADED. +erlfdb_database_open_tenant(_Database, _TenantName) -> ?NOT_LOADED. erlfdb_database_set_option(_Database, _DatabaseOption, _Value) -> ?NOT_LOADED. erlfdb_database_create_transaction(_Database) -> ?NOT_LOADED. +erlfdb_tenant_create_transaction(_Tenant) -> ?NOT_LOADED. % Transactions erlfdb_transaction_set_option(_Transaction, _TransactionOption, _Value) -> ?NOT_LOADED. diff --git a/src/erlfdb_tenant_management.erl b/src/erlfdb_tenant_management.erl new file mode 100644 index 0000000..597f896 --- /dev/null +++ b/src/erlfdb_tenant_management.erl @@ -0,0 +1,54 @@ +-module(erlfdb_tenant_management). + +-export([transactional/2, list_tenants/1, list_tenants/4, get_tenant/2, create_tenant/2, delete_tenant/2]). + +-define(TENANT_MAP(TenantName), iolist_to_binary([<<16#FF, 16#FF, "/management/tenant/map/">>, TenantName])). + +-define(IS_DB, {erlfdb_database, _}). +-define(IS_TX, {erlfdb_transaction, _}). + +transactional(?IS_DB = Db, UserFun) -> + erlfdb:transactional(Db, fun(Tx) -> + ok = erlfdb:set_option(Tx, special_key_space_enable_writes), + UserFun(Tx) + end). + +list_tenants(DbOrTx) -> + % Tenant names cannot start with \xff, so this is guaranteed to get all tenants + list_tenants(DbOrTx, <<>>, <<16#FF>>, []). + +list_tenants(?IS_DB = Db, Begin, End, Opts) -> + erlfdb:transactional(Db, fun(Tx) -> + ok = erlfdb:set_option(Tx, read_system_keys), + erlfdb:wait(list_tenants(Tx, Begin, End, Opts)) + end); +list_tenants(?IS_TX = Tx, Begin, End, Opts) -> + erlfdb:get_range(Tx, ?TENANT_MAP(Begin), ?TENANT_MAP(End), Opts). + +get_tenant(?IS_DB = Db, TenantName) -> + erlfdb:transactional(Db, fun(Tx) -> + ok = erlfdb:set_option(Tx, read_system_keys), + erlfdb:wait(get_tenant(Tx, TenantName)) + end); +get_tenant(?IS_TX = Tx, TenantName) -> + erlfdb:get(Tx, ?TENANT_MAP(TenantName)). + +create_tenant(?IS_DB = Db, TenantName) -> + transactional(Db, fun(Tx) -> + case erlfdb:wait(get_tenant(Tx, TenantName)) of + not_found -> + erlfdb:wait(create_tenant(Tx, TenantName)); + _ -> + % tenant_already_exists + erlang:error({erlfdb_error, 2132}) + end + end); +create_tenant(?IS_TX = Tx, TenantName) -> + erlfdb:set(Tx, ?TENANT_MAP(TenantName), <<>>). + +delete_tenant(?IS_DB = Db, TenantName) -> + transactional(Db, fun(Tx) -> + erlfdb:wait(delete_tenant(Tx, TenantName)) + end); +delete_tenant(?IS_TX = Tx, TenantName) -> + erlfdb:clear(Tx, ?TENANT_MAP(TenantName)). diff --git a/src/erlfdb_util.erl b/src/erlfdb_util.erl index 08ed4ff..3a53147 100644 --- a/src/erlfdb_util.erl +++ b/src/erlfdb_util.erl @@ -18,6 +18,9 @@ init_test_cluster/1, + create_and_open_test_tenant/2, + clear_and_delete_test_tenant/1, + get/2, get/3, @@ -27,21 +30,14 @@ debug_cluster/3 ]). +-define(TEST_TENANT_NAME, <>). + get_test_db() -> get_test_db([]). get_test_db(Options) -> {ok, ClusterFile} = init_test_cluster(Options), - Db = erlfdb:open(ClusterFile), - case proplists:get_value(empty, Options) of - true -> - erlfdb:transactional(Db, fun(Tx) -> - erlfdb:clear_range(Tx, <<>>, <<16#FE, 16#FF, 16#FF, 16#FF>>) - end); - _ -> - ok - end, - Db. + erlfdb:open(ClusterFile). init_test_cluster(Options) -> % Hack to ensure erlfdb app environment is loaded during unit tests @@ -55,6 +51,52 @@ init_test_cluster(Options) -> init_test_cluster_int(Options) end. +create_and_open_test_tenant(Db, Options) -> + case proplists:get_value(empty, Options) of + true -> + clear_test_tenant(Db); + _ -> + ok + end, + erlfdb_tenant_management:transactional(Db, + fun(Tx) -> + case erlfdb:wait(erlfdb_tenant_management:get_tenant(Tx, ?TEST_TENANT_NAME)) of + not_found -> + erlfdb_tenant_management:create_tenant(Tx, ?TEST_TENANT_NAME); + _ -> + ok + end + end), + erlfdb:open_tenant(Db, ?TEST_TENANT_NAME). + +clear_test_tenant(Db) -> + TenantClearFun = + fun(Tx) -> + case erlfdb:wait(erlfdb:get_range(Tx, <<>>, <<16#FF>>, [{limit, 1}])) of + [] -> + ok; + _ -> + erlfdb:clear_range(Tx, <<>>, <<16#FE, 16#FF, 16#FF, 16#FF>>) + end + end, + Tenant = erlfdb:open_tenant(Db, ?TEST_TENANT_NAME), + erlfdb:transactional(Tenant, TenantClearFun). + +clear_and_delete_test_tenant(Db) -> + TenantDeleteFun = + fun(Tx) -> + case erlfdb:wait(erlfdb_tenant_management:get_tenant(Tx, ?TEST_TENANT_NAME)) of + not_found -> + ok; + _ -> + % embedded transaction + clear_test_tenant(Db), + + erlfdb_tenant_management:delete_tenant(Db, ?TEST_TENANT_NAME) + end + end, + erlfdb_tenant_management:transactional(Db, TenantDeleteFun). + get(List, Key) -> get(List, Key, undefined). diff --git a/test/erlfdb_02_anon_fdbserver_test.erl b/test/erlfdb_02_anon_fdbserver_test.erl index ebfd020..14f149f 100644 --- a/test/erlfdb_02_anon_fdbserver_test.erl +++ b/test/erlfdb_02_anon_fdbserver_test.erl @@ -21,51 +21,61 @@ basic_init_test() -> basic_open_test() -> {ok, ClusterFile} = erlfdb_util:init_test_cluster([]), Db = erlfdb:open(ClusterFile), - erlfdb:transactional(Db, fun(Tx) -> + erlfdb:transactional(Db, fun(_Tx) -> ?assert(true) end). get_db_test() -> Db = erlfdb_util:get_test_db(), - erlfdb:transactional(Db, fun(Tx) -> + erlfdb:transactional(Db, fun(_Tx) -> ?assert(true) end). get_set_get_test() -> Db = erlfdb_util:get_test_db(), - Key = gen_key(8), - Val = crypto:strong_rand_bytes(8), - erlfdb:transactional(Db, fun(Tx) -> - ?assertEqual(not_found, erlfdb:wait(erlfdb:get(Tx, Key))) - end), - erlfdb:transactional(Db, fun(Tx) -> - ?assertEqual(ok, erlfdb:set(Tx, Key, Val)) - end), - erlfdb:transactional(Db, fun(Tx) -> - ?assertEqual(Val, erlfdb:wait(erlfdb:get(Tx, Key))) - end). + get_set_get(Db). get_empty_test() -> - Db1 = erlfdb_util:get_test_db(), + Db = erlfdb_util:get_test_db(), + Tenant1 = erlfdb_util:create_and_open_test_tenant(Db, []), Key = gen_key(8), Val = crypto:strong_rand_bytes(8), - erlfdb:transactional(Db1, fun(Tx) -> + erlfdb:transactional(Tenant1, fun(Tx) -> ok = erlfdb:set(Tx, Key, Val) end), - erlfdb:transactional(Db1, fun(Tx) -> + erlfdb:transactional(Tenant1, fun(Tx) -> ?assertEqual(Val, erlfdb:wait(erlfdb:get(Tx, Key))) end), % Check we can get an empty db - Db2 = erlfdb_util:get_test_db([empty]), - erlfdb:transactional(Db2, fun(Tx) -> + Tenant2 = erlfdb_util:create_and_open_test_tenant(Db, [empty]), + erlfdb:transactional(Tenant2, fun(Tx) -> ?assertEqual(not_found, erlfdb:wait(erlfdb:get(Tx, Key))) end), % And check state that the old db handle is % the same - erlfdb:transactional(Db1, fun(Tx) -> + erlfdb:transactional(Tenant1, fun(Tx) -> + ?assertEqual(not_found, erlfdb:wait(erlfdb:get(Tx, Key))) + end). + +get_set_get_tenant_test() -> + Db = erlfdb_util:get_test_db(), + Tenant = erlfdb_util:create_and_open_test_tenant(Db, []), + get_set_get(Tenant), + erlfdb_util:clear_and_delete_test_tenant(Db). + +get_set_get(DbOrTenant) -> + Key = gen_key(8), + Val = crypto:strong_rand_bytes(8), + erlfdb:transactional(DbOrTenant, fun(Tx) -> ?assertEqual(not_found, erlfdb:wait(erlfdb:get(Tx, Key))) + end), + erlfdb:transactional(DbOrTenant, fun(Tx) -> + ?assertEqual(ok, erlfdb:set(Tx, Key, Val)) + end), + erlfdb:transactional(DbOrTenant, fun(Tx) -> + ?assertEqual(Val, erlfdb:wait(erlfdb:get(Tx, Key))) end). gen_key(Size) when is_integer(Size), Size > 1 -> From 075c9b879dee7542617587dcd0d5378ee831b4b4 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Sun, 4 Feb 2024 13:07:38 -0500 Subject: [PATCH 2/6] Enable tentants on test cluster --- src/erlfdb_util.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/erlfdb_util.erl b/src/erlfdb_util.erl index 3a53147..4995f2b 100644 --- a/src/erlfdb_util.erl +++ b/src/erlfdb_util.erl @@ -260,7 +260,7 @@ init_fdb_db(ClusterFile, Options) -> DefaultFDBCli -> "fdbcli"; FDBCli0 -> FDBCli0 end, - Fmt = "~s -C ~s --exec \"configure new single ssd\"", + Fmt = "~s -C ~s --exec \"configure new single ssd tenant_mode=optional_experimental\"", Cmd = lists:flatten(io_lib:format(Fmt, [FDBCli, ClusterFile])), case os:cmd(Cmd) of "Database created" ++ _ -> ok; From b2cf25a20b266537df34d40aaa27c24a6a212acc Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Sun, 4 Feb 2024 13:16:24 -0500 Subject: [PATCH 3/6] Use explicit machine id to avoid required shared memory access --- src/erlfdb_util.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/erlfdb_util.erl b/src/erlfdb_util.erl index 4995f2b..6fc7b2a 100644 --- a/src/erlfdb_util.erl +++ b/src/erlfdb_util.erl @@ -30,6 +30,9 @@ debug_cluster/3 ]). +% Some systems are unable to compute the shared machine id without root, +% so we'll provide a hardcoded machine id for our managed fdbserver +-define(TEST_CLUSTER_MACHINE_ID, <>). -define(TEST_TENANT_NAME, <>). get_test_db() -> @@ -167,7 +170,9 @@ init_test_cluster_int(Options) -> <<"-d">>, Dir, <<"-L">>, - Dir + Dir, + <<"-i">>, + ?TEST_CLUSTER_MACHINE_ID ], FDBPortOpts = [{args, FDBPortArgs}], FDBServer = erlang:open_port(FDBPortName, FDBPortOpts), From 59d4a1dcb727bd84b86f9b8cbb3a8e7da585f128 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Sun, 4 Feb 2024 19:47:22 -0500 Subject: [PATCH 4/6] Expose utility functions for downstream testers --- src/erlfdb_util.erl | 55 ++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/erlfdb_util.erl b/src/erlfdb_util.erl index 6fc7b2a..ed16789 100644 --- a/src/erlfdb_util.erl +++ b/src/erlfdb_util.erl @@ -19,7 +19,13 @@ init_test_cluster/1, create_and_open_test_tenant/2, + create_and_open_tenant/3, + clear_and_delete_test_tenant/1, + clear_and_delete_tenant/2, + + clear_test_tenant/1, + clear_tenant/2, get/2, get/3, @@ -55,51 +61,60 @@ init_test_cluster(Options) -> end. create_and_open_test_tenant(Db, Options) -> + create_and_open_tenant(Db, Options, ?TEST_TENANT_NAME). + +create_and_open_tenant(Db, Options, TenantName) -> case proplists:get_value(empty, Options) of true -> - clear_test_tenant(Db); + clear_tenant(Db, TenantName); _ -> ok end, erlfdb_tenant_management:transactional(Db, fun(Tx) -> - case erlfdb:wait(erlfdb_tenant_management:get_tenant(Tx, ?TEST_TENANT_NAME)) of + case erlfdb:wait(erlfdb_tenant_management:get_tenant(Tx, TenantName)) of not_found -> - erlfdb_tenant_management:create_tenant(Tx, ?TEST_TENANT_NAME); + erlfdb_tenant_management:create_tenant(Tx, TenantName); _ -> ok end end), - erlfdb:open_tenant(Db, ?TEST_TENANT_NAME). - -clear_test_tenant(Db) -> - TenantClearFun = - fun(Tx) -> - case erlfdb:wait(erlfdb:get_range(Tx, <<>>, <<16#FF>>, [{limit, 1}])) of - [] -> - ok; - _ -> - erlfdb:clear_range(Tx, <<>>, <<16#FE, 16#FF, 16#FF, 16#FF>>) - end - end, - Tenant = erlfdb:open_tenant(Db, ?TEST_TENANT_NAME), - erlfdb:transactional(Tenant, TenantClearFun). + erlfdb:open_tenant(Db, TenantName). clear_and_delete_test_tenant(Db) -> + clear_and_delete_tenant(Db, ?TEST_TENANT_NAME). + +clear_and_delete_tenant(Db, TenantName) -> TenantDeleteFun = fun(Tx) -> - case erlfdb:wait(erlfdb_tenant_management:get_tenant(Tx, ?TEST_TENANT_NAME)) of + case erlfdb:wait(erlfdb_tenant_management:get_tenant(Tx, TenantName)) of not_found -> ok; _ -> % embedded transaction - clear_test_tenant(Db), + clear_tenant(Db, TenantName), - erlfdb_tenant_management:delete_tenant(Db, ?TEST_TENANT_NAME) + erlfdb_tenant_management:delete_tenant(Db, TenantName) end end, erlfdb_tenant_management:transactional(Db, TenantDeleteFun). +clear_test_tenant(Db) -> + clear_tenant(Db, ?TEST_TENANT_NAME). + +clear_tenant(Db, TenantName) -> + TenantClearFun = + fun(Tx) -> + case erlfdb:wait(erlfdb:get_range(Tx, <<>>, <<16#FF>>, [{limit, 1}])) of + [] -> + ok; + _ -> + erlfdb:clear_range(Tx, <<>>, <<16#FE, 16#FF, 16#FF, 16#FF>>) + end + end, + Tenant = erlfdb:open_tenant(Db, TenantName), + erlfdb:transactional(Tenant, TenantClearFun). + get(List, Key) -> get(List, Key, undefined). From c631735d8f8fc502c66cdc09aa9f952d994e8d0a Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Sun, 4 Feb 2024 20:03:55 -0500 Subject: [PATCH 5/6] Fix empty tenant util --- src/erlfdb_util.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/erlfdb_util.erl b/src/erlfdb_util.erl index ed16789..3048371 100644 --- a/src/erlfdb_util.erl +++ b/src/erlfdb_util.erl @@ -66,7 +66,7 @@ create_and_open_test_tenant(Db, Options) -> create_and_open_tenant(Db, Options, TenantName) -> case proplists:get_value(empty, Options) of true -> - clear_tenant(Db, TenantName); + clear_and_delete_tenant(Db, TenantName); _ -> ok end, From 0c1ea2ae457924f36fa1dbdb4b5bf8f52ce1ad24 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Mon, 12 Feb 2024 11:28:35 -0500 Subject: [PATCH 6/6] Fix failing test --- src/erlfdb_util.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/erlfdb_util.erl b/src/erlfdb_util.erl index 3048371..e50789f 100644 --- a/src/erlfdb_util.erl +++ b/src/erlfdb_util.erl @@ -66,7 +66,12 @@ create_and_open_test_tenant(Db, Options) -> create_and_open_tenant(Db, Options, TenantName) -> case proplists:get_value(empty, Options) of true -> - clear_and_delete_tenant(Db, TenantName); + case erlfdb_tenant_management:get_tenant(Db, TenantName) of + not_found -> + ok; + _ -> + clear_tenant(Db, TenantName) + end; _ -> ok end,