More on admin and configuration
This tutorial provides more information on the admin interface and on configuring the server and its databases.
The admin interface
The admin library provides functions to open, close, destroy, and list databases. This API is showcased in the code bellow.
admin.c (show/hide)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <margo.h>
#include <yokan/admin.h>
int main(int argc, char** argv)
{
if(argc != 3) {
fprintf(stderr, "Usage: %s <address> <provider id>\n", argv[0]);
exit(-1);
}
margo_instance_id mid = margo_init("na+sm", MARGO_CLIENT_MODE, 0, 0);
assert(mid);
uint16_t provider_id = atoi(argv[2]);
hg_addr_t server_addr = HG_ADDR_NULL;
hg_return_t hret = margo_addr_lookup(mid, argv[1], &server_addr);
assert(hret == HG_SUCCESS);
yk_return_t ret;
yk_admin_t admin = YOKAN_ADMIN_NULL;
yk_database_id_t db_id;
ret = yk_admin_init(mid, &admin);
assert(ret == YOKAN_SUCCESS);
ret = yk_open_database(admin, server_addr, provider_id,
"ABCD", "map", "{}", &db_id);
assert(ret == YOKAN_SUCCESS);
yk_database_id_t db_ids[4];
size_t db_count = 4;
ret = yk_list_databases(admin, server_addr, provider_id,
"ABCD", db_ids, &db_count);
assert(ret == YOKAN_SUCCESS);
printf("Found %lu databases in provider:\n", db_count);
for(int i=0; i < db_count; i++) {
char db_id_str[37];
yk_database_id_to_string(db_ids[i], db_id_str);
printf("\t%s\n", db_id_str);
}
ret = yk_close_database(admin, server_addr, provider_id,
"ABCD", db_ids[0]);
assert(ret == yokan_success);
ret = yk_destroy_database(admin, server_addr, provider_id,
"ABCD", db_ids[1]);
assert(ret == yokan_success);
ret = yk_admin_finalize(admin);
assert(ret == yokan_success);
margo_finalize(mid);
return 0;
}
Depending on the backend used, opening a database may create files, or request to open existing files. Closing a database will make it inaccessible to clients. If the database was in memory, it will also erase its contents. If it was backed up by files, it will close those files. Destroying the database will not only close it, it will also erase all corresponding files from the unerlying file system.
The code above also shows the use of security tokens (“ABCD”). This mechanism is a rudimentary security check. This string can be used when initializing a provider so that operations from the admin library need the same token to proceed. These token are generally not needed in most use cases and can be set to NULL.
Creating databases without an admin
In the previous tutorial we have hand-written an admin program to create a database. This is not needed, however, as we could have put the database definition directly in the Bedrock configuration file, as follows.
{
"libraries": {
"yokan": "libyokan-bedrock-module.so"
},
"providers": [
{
"name" : "my_yokan_provider",
"type" : "yokan",
"provider_id" : 42,
"pool" : "__primary__",
"config" : {
"databases": [
{
"type": "map"
}
]
},
"dependencies" : {}
}
]
}
By doing so, we see in Bedrock’s standard output the database being created, and we can grab its identifier.
$ bedrock na+sm -c config.json.
[2021-10-14 12:16:24.608] [info] [yokan] opened database 0361eb8b-d739-4950-89a2-26f16ea3db
[2021-10-14 12:16:24.608] [info] [yokan] YOKAN provider registration done
[2021-10-14 12:16:24.608] [info] Bedrock daemon now running at na+sm://8972-0
Similarly, when embedding a provider into C code, we can pass a configuration string that contains the definition of a database, as follows.
server.c (show/hide)
#include <assert.h>
#include <stdio.h>
#include <margo.h>
#include <yokan/server.h>
static const char* config =
"{ \"databases\": ["
"{ \"type\": \"map\" }"
"]}"
;
int main(int argc, char** argv)
{
margo_instance_id mid = margo_init("na+sm", MARGO_SERVER_MODE, 0, 0);
assert(mid);
hg_addr_t my_address;
margo_addr_self(mid, &my_address);
char addr_str[128];
size_t addr_str_size = 128;
margo_addr_to_string(mid, addr_str, &addr_str_size, my_address);
margo_addr_free(mid,my_address);
margo_set_log_level(mid, MARGO_LOG_INFO);
margo_info(mid, "Server running at address %s", addr_str);
struct yk_provider_args args = {
.token = "ABCD",
.config = config,
.pool = ABT_POOL_NULL,
.cache = NULL
};
yk_return_t ret = yk_provider_register(mid, 42, &args, YOKAN_PROVIDER_IGNORE);
assert(ret == YOKAN_SUCCESS);
margo_wait_for_finalize(mid);
return 0;
}