Hello,
OS: Centos 7.
FDB: 5.1.7.
i’m trying to implement secondary index with C API, but i can’t make it work (entire code at end):
const std::string key = "try29:";
for (int i = 0; i < 10; i++)
{
auto [res, ts] = getKeyTS(db, key);
std::cout << key << " = [" << res << "]; ts = " << std::hex << ts << std::dec << std::endl;
res += std::to_string(i);
res.append(",");
updateKeyTS(db, key, ts, res);
sleep(1);
}
i make a loop and updating the same key 10 times,
actually i got an output:
try29: = []; ts = 0
try29: = []; ts = 0
try29: = [0,]; ts = 5afd78dc
try29: = [1,]; ts = 5afd78dd
try29: = [0,2,]; ts = 5afd78de
try29: = [1,3,]; ts = 5afd78df
try29: = [0,2,4,]; ts = 5afd78e0
try29: = [1,3,5,]; ts = 5afd78e1
try29: = [0,2,4,6,]; ts = 5afd78e2
try29: = [1,3,5,7,]; ts = 5afd78e3
this is not expected, i hope to see one variable collecting all digits.
if i remove sleep - output will be something like that:
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
try30: = []; ts = 0
this result is trange as well, why it differ from previous one ?
i must be wrong somewhere,
any help ?
PS:
full code
#include <chrono>
#include <cstring>
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <sstream>
#include <unistd.h>
#define FDB_API_VERSION 510
#include <fdb_c.h>
/*
g++ t1.cpp -I/usr/include/foundationdb -lfdb_c -O3 -ggdb -pthread -std=c++17
*/
void checkError(fdb_error_t errorNum)
{
if(errorNum) { fprintf(stderr, "Error (%d): %s\n", errorNum, fdb_get_error(errorNum)); exit(errorNum); }
}
void waitAndCheckError(FDBFuture *future)
{
checkError(fdb_future_block_until_ready(future));
fdb_error_t r = fdb_future_get_error(future);
if (0 != r)
checkError(r);
}
void openDatabase(FDBCluster **cluster, FDBDatabase **db)
{
FDBFuture *clusterFuture = fdb_create_cluster("/etc/foundationdb/fdb.cluster");
waitAndCheckError(clusterFuture);
checkError(fdb_future_get_cluster(clusterFuture, cluster));
fdb_future_destroy(clusterFuture);
std::cout << "got cluster" << std::endl;
FDBFuture *dbFuture = fdb_cluster_create_database(*cluster, (const uint8_t*)"DB", 2);
waitAndCheckError(dbFuture);
checkError(fdb_future_get_database(dbFuture, db));
fdb_future_destroy(dbFuture);
std::cout << "got database" << std::endl;
}
void closeDatabase(FDBCluster *cluster, FDBDatabase *db)
{
fdb_database_destroy(db);
fdb_cluster_destroy(cluster);
}
// key + timestamp
std::pair<std::string, time_t> getKeyTS(FDBDatabase *db, const std::string& key)
{
time_t ts = 0;
std::string result;
FDBTransaction *tr;
checkError(fdb_database_create_transaction(db, &tr));
std::string end_key = key + "z"; // no `z` char in timestamp
// FDBTransaction* transaction,
// uint8_t const* begin_key_name, int begin_key_name_length, fdb_bool_t begin_or_equal, int begin_offset,
// uint8_t const* end_key_name, int end_key_name_length fdb_bool_t end_or_equal, int end_offset,
// int limit, int target_bytes,
// FDBStreamingMode mode, int iteration,
// fdb_bool_t snapshot, fdb_bool_t reverse
FDBFuture *getFuture = fdb_transaction_get_range(tr,
FDB_KEYSEL_FIRST_GREATER_THAN((const uint8_t*)key.c_str(), key.size()),
FDB_KEYSEL_LAST_LESS_THAN((const uint8_t*)end_key.c_str(), end_key.size()),
10, 0,
FDB_STREAMING_MODE_WANT_ALL, 0,
0, 0);
// fdb_transaction_get_range(tr, FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[0], keySize), FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[numKeys], keySize),
// numKeys, 0, 0, 1, 0, 0);
waitAndCheckError(getFuture);
fdb_bool_t valuePresent;
FDBKeyValue const* res;
int count = 0;
fdb_bool_t more;
checkError(fdb_future_get_keyvalue_array(getFuture, &res, &count, &more));
//std::cout << "found " << count << " entries" << std::endl;
if (count > 0)
{
std::string key((const char*)res->key, res->key_length);
if (key.size() > 8)
ts = std::strtol(key.c_str() + key.size() - 8, 0, 16);
result.assign((const char*)res->value, res->value_length);
}
fdb_future_destroy(getFuture);
fdb_transaction_destroy(tr);
return std::make_pair(result, ts);
}
std::pair<std::string, std::string> makeKeyTS(const std::string& key, const time_t ts = ::time(0))
{
std::stringstream stream;
stream << std::hex << ts;
const std::string hextime = stream.str();
const std::string norm_key = key + hextime;
const std::string rev_key = hextime + key;
return std::make_pair(norm_key, rev_key);
}
void updateKeyTS(FDBDatabase *db, const std::string& key, const time_t ts, const std::string& value)
{
FDBTransaction *tr;
checkError(fdb_database_create_transaction(db, &tr));
// rm old
{
auto [norm_key, rev_key] = makeKeyTS(key, ts);
fdb_transaction_clear(tr, (const uint8_t*)norm_key.c_str(), (int)norm_key.size());
fdb_transaction_clear(tr, (const uint8_t*)rev_key.c_str(), (int)rev_key.size());
}
// put new
{
auto [norm_key, rev_key] = makeKeyTS(key);
fdb_transaction_set(tr,
(const uint8_t*)norm_key.c_str(), (int)norm_key.size(),
(const uint8_t*)value.c_str(), (int)value.size());
fdb_transaction_set(tr,
(const uint8_t*)rev_key.c_str(), (int)rev_key.size(),
(const uint8_t*)0, 0);
}
FDBFuture *getFuture = fdb_transaction_commit(tr);
waitAndCheckError(getFuture);
fdb_future_destroy(getFuture);
fdb_transaction_destroy(tr);
}
void f3(void)
{
FDBCluster *cluster;
FDBDatabase *db;
openDatabase(&cluster, &db);
const std::string key = "try30:";
for (int i = 0; i < 10; i++)
{
auto [res, ts] = getKeyTS(db, key);
std::cout << key << " = [" << res << "]; ts = " << std::hex << ts << std::dec << std::endl;
res += std::to_string(i);
res.append(",");
updateKeyTS(db, key, ts, res);
sleep(1);
}
closeDatabase(cluster, db);
}
int main(void)
{
checkError(fdb_select_api_version(FDB_API_VERSION));
checkError(fdb_setup_network());
std::thread fdbt([]{
checkError(fdb_run_network());
});
std::cerr << "sleeping" << std::endl;
sleep(1);
f3();
std::cerr << "stopping" << std::endl;
checkError(fdb_stop_network());
std::cerr << "joining" << std::endl;
fdbt.join();
return 0;
}