diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index fb9e43c..269091b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,6 @@ ARG FDB_VERSION ARG ERLANG_VERSION +ARG PIP_INSTALL_FLAGS # Grab fdbcli and client library from same image as server FROM foundationdb/foundationdb:${FDB_VERSION} as fdb @@ -13,7 +14,7 @@ ARG FDB_VERSION # Install the FDB client used underneath erlfdb RUN set -ex; \ - wget https://github.com/apple/foundationdb/releases/download/${FDB_VERSION}/foundationdb-clients_${FDB_VERSION}-1_amd64.deb; \ + wget -q https://github.com/apple/foundationdb/releases/download/${FDB_VERSION}/foundationdb-clients_${FDB_VERSION}-1_amd64.deb; \ mkdir /var/lib/foundationdb; \ dpkg -i foundationdb-clients_${FDB_VERSION}-1_amd64.deb; \ rm foundationdb-clients_${FDB_VERSION}-1_amd64.deb @@ -36,8 +37,10 @@ RUN set -ex; \ python3-pip; \ rm -rf /var/lib/apt/lists/* +ARG PIP_INSTALL_FLAGS + # FDB bindings tester uses the Python bindings -RUN pip3 install foundationdb==${FDB_VERSION} +RUN pip3 install foundationdb==${FDB_VERSION} ${PIP_INSTALL_FLAGS} COPY create_cluster_file.bash /usr/local/bin/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8be2b83..b139c01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,9 @@ jobs: matrix: otp-version: ['25', '26'] fdb-version: ['7.3.35'] + services: + foundationdb: + image: foundationdb/foundationdb:7.3.35 runs-on: ubuntu-22.04 env: FDB_VERSION: ${{ matrix.fdb-version }} @@ -31,12 +34,15 @@ jobs: with: otp-version: ${{ matrix.otp-version }} rebar3-version: '3.17' - - name: Install FoundationDB - run: | - wget https://github.com/apple/foundationdb/releases/download/${FDB_VERSION}/foundationdb-clients_${FDB_VERSION}-1_amd64.deb - wget https://github.com/apple/foundationdb/releases/download/${FDB_VERSION}/foundationdb-server_${FDB_VERSION}-1_amd64.deb - sudo dpkg -i foundationdb-clients_${FDB_VERSION}-1_amd64.deb - sudo dpkg -i foundationdb-server_${FDB_VERSION}-1_amd64.deb + - name: Create FDB cluster file + env: + # This needs to match the name of the service above so the script can do + # a DNS lookup to write down the coordinator IP in the fdb.cluster file + FDB_COORDINATOR: foundationdb + shell: bash + run: sudo bash .devcontainer/create_cluster_file.bash + - name: Initialize FDB database + run: fdbcli --exec "configure new single ssd tenant_mode=optional_experimental" - name: Compile run: rebar3 compile - name: EUnit tests diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2889a4a..df66f23 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,7 +16,11 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - otp-version: ['25', '26'] + otp: + - version: 25 + pip_flags: '' + - version: 26 + pip_install_flags: '--break-system-packages' fdb-version: ['7.3.35'] steps: @@ -31,9 +35,10 @@ jobs: - uses: docker/build-push-action@v3 with: push: true - tags: ghcr.io/${{ github.repository }}:erlang-${{ matrix.otp-version }}-fdb-${{ matrix.fdb-version }} + tags: ghcr.io/${{ github.repository }}:erlang-${{ matrix.otp.version }}-fdb-${{ matrix.fdb-version }} file: .devcontainer/Dockerfile context: .devcontainer build-args: | FDB_VERSION=${{ matrix.fdb-version }} - ERLANG_VERSION=${{ matrix.otp-version }} + ERLANG_VERSION=${{ matrix.otp.version }} + PIP_INSTALL_FLAGS=${{ matrix.otp.pip_install_flags }} diff --git a/c_src/main.c b/c_src/main.c index 006303b..9a96400 100644 --- a/c_src/main.c +++ b/c_src/main.c @@ -828,6 +828,37 @@ erlfdb_database_open_tenant( } +static ERL_NIF_TERM +erlfdb_tenant_get_id( + ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[] + ) +{ + ErlFDBSt* st = (ErlFDBSt*) enif_priv_data(env); + ErlFDBTenant* t; + void* res; + FDBFuture* future; + + 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); + } + t = (ErlFDBTenant*) res; + + future = fdb_tenant_get_id(t->tenant); + + return erlfdb_create_future(env, future, erlfdb_future_get_int64); +} + + static ERL_NIF_TERM erlfdb_tenant_create_transaction( ErlNifEnv* env, @@ -2272,6 +2303,7 @@ 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_tenant_get_id, 1), NIF_FUNC(erlfdb_database_create_transaction, 1), NIF_FUNC(erlfdb_tenant_create_transaction, 1), diff --git a/src/erlfdb_nif.erl b/src/erlfdb_nif.erl index d723c26..f64de9b 100644 --- a/src/erlfdb_nif.erl +++ b/src/erlfdb_nif.erl @@ -33,6 +33,7 @@ database_create_transaction/1, tenant_create_transaction/1, + tenant_get_id/1, transaction_set_option/2, transaction_set_option/3, @@ -294,6 +295,10 @@ database_create_transaction({erlfdb_database, Db}) -> tenant_create_transaction({erlfdb_tenant, Db}) -> erlfdb_tenant_create_transaction(Db). +-spec tenant_get_id(tenant()) -> future(). +tenant_get_id({erlfdb_tenant, Db}) -> + erlfdb_tenant_get_id(Db). + -spec transaction_set_option(transaction(), Option :: transaction_option()) -> ok. transaction_set_option(Transaction, Option) -> transaction_set_option(Transaction, Option, <<>>). @@ -580,6 +585,7 @@ erlfdb_database_create_transaction(_Database) -> ?NOT_LOADED. %% Tenants erlfdb_tenant_create_transaction(_Database) -> ?NOT_LOADED. +erlfdb_tenant_get_id(_Tenant) -> ?NOT_LOADED. % Transactions erlfdb_transaction_set_option(_Transaction, _TransactionOption, _Value) -> ?NOT_LOADED. diff --git a/src/erlfdb_tenant.erl b/src/erlfdb_tenant.erl index e8c67d0..2f3cceb 100644 --- a/src/erlfdb_tenant.erl +++ b/src/erlfdb_tenant.erl @@ -12,10 +12,10 @@ -module(erlfdb_tenant). --export([create_tenant/2, open_tenant/2, delete_tenant/2, list_tenants/4]). +-export([create_tenant/2, open_tenant/2, delete_tenant/2, list_tenants/4, get_id/1]). -define(IS_DB, {erlfdb_database, _}). --define(TENANT_MAP_PREFIX, <<16#FF, 16#FF, "/management/tenant_map/">>). +-define(TENANT_MAP_PREFIX, <<16#FF, 16#FF, "/management/tenant/map/">>). -define(MAX_LIMIT, 2147483647). -import(erlfdb, [get/2, clear/2, set/3, wait/1, transactional/2, set_option/2]). @@ -59,6 +59,9 @@ list_tenants(Db, From, To, Limit) -> [] end. +get_id(Tenant) -> + erlfdb_nif:tenant_get_id(Tenant). + do_list_tenants(?IS_DB = Db, From, To, Limit) -> transactional(Db, fun(Tx) -> list_tenants(Tx, From, To, Limit) diff --git a/test/erlfdb_07_tenant_test.erl b/test/erlfdb_07_tenant_test.erl new file mode 100644 index 0000000..844100b --- /dev/null +++ b/test/erlfdb_07_tenant_test.erl @@ -0,0 +1,47 @@ +% Licensed 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(erlfdb_07_tenant_test). + +-include_lib("eunit/include/eunit.hrl"). + +tenant_management_test() -> + Db = erlfdb_util:get_test_db(), + Tenant = gen(10), + ?assertEqual(ok, erlfdb_tenant:create_tenant(Db, Tenant)), + ?assertEqual({error, tenant_already_exists}, erlfdb_tenant:create_tenant(Db, Tenant)), + ?assertEqual(ok, erlfdb_tenant:delete_tenant(Db, Tenant)), + ?assertEqual({error, tenant_not_found}, erlfdb_tenant:delete_tenant(Db, Tenant)). + +tenant_list_test() -> + Db = erlfdb_util:get_test_db(), + Tenant1 = gen(10), + Tenant2 = gen(10), + ?assertEqual(ok, erlfdb_tenant:create_tenant(Db, Tenant1)), + ?assertEqual(ok, erlfdb_tenant:create_tenant(Db, Tenant2)), + {Tenants, _} = lists:unzip(erlfdb_tenant:list_tenants(Db, <<>>, <<16#FF>>, 99999999)), + ?assert(lists:member(Tenant1, Tenants)), + ?assert(lists:member(Tenant2, Tenants)). + +tenant_get_id_test() -> + Db = erlfdb_util:get_test_db(), + Tenant = gen(10), + ?assertEqual(ok, erlfdb_tenant:create_tenant(Db, Tenant)), + Tn = erlfdb_tenant:open_tenant(Db, Tenant), + ?assert(is_integer(erlfdb:wait(erlfdb_tenant:get_id(Tn)))). + +gen(N) -> + << <<(gen_char())>> || _ <- lists:seq(1, N) >>. + +gen_char() -> + $a - 1 + rand:uniform($z - $a + 1). + diff --git a/test/tester.es b/test/tester.es index 3bbaa04..672530d 100755 --- a/test/tester.es +++ b/test/tester.es @@ -795,7 +795,7 @@ execute(_TxObj, #st{tenant = Tenant} = St, <<"TENANT_GET_ID">>) -> case Tenant of undefined -> stack_push(St, <<"NO_ACTIVE_TENANT">>); _ -> - %% TODO: get tenant id actually + _Id = erlfdb:wait(erlfdb_tenant:get_id(Tenant)), stack_push(St, <<"GOT_TENANT_ID">>) end, St;