Commit ca74a8b4 authored by Matthieu Dorier's avatar Matthieu Dorier
Browse files

done adapting to C++ interface

parent 837650b2
......@@ -6,9 +6,6 @@
#include <vector>
#include <functional>
#include <iostream>
#include <yaml-cpp/yaml.h>
#include <sdskv-client.h>
#include <ch-placement.h>
#include "hepnos/Exception.hpp"
#include "hepnos/DataStore.hpp"
#include "hepnos/DataSet.hpp"
......
......@@ -12,9 +12,9 @@
#include <functional>
#include <iostream>
#include <yaml-cpp/yaml.h>
#include <sdskv-client.h>
#include <sdskv-client.hpp>
#include <ch-placement.h>
#include "KeyTypes.hpp"
//#include "KeyTypes.hpp"
#include "hepnos/Exception.hpp"
#include "hepnos/DataStore.hpp"
#include "hepnos/DataSet.hpp"
......@@ -28,21 +28,15 @@ namespace hepnos {
class DataStore::Impl {
public:
struct database {
sdskv_provider_handle_t m_sdskv_ph;
sdskv_database_id_t m_sdskv_db;
};
margo_instance_id m_mid; // Margo instance
std::unordered_map<std::string,hg_addr_t> m_addrs; // Addresses used by the service
sdskv_client_t m_sdskv_client; // SDSKV client
std::vector<database> m_databases; // list of SDSKV databases
sdskv::client m_sdskv_client; // SDSKV client
std::vector<sdskv::database> m_databases; // list of SDSKV databases
struct ch_placement_instance* m_chi_sdskv; // ch-placement instance for SDSKV
const DataStore::iterator m_end; // iterator for the end() of the DataStore
Impl(DataStore* parent)
: m_mid(MARGO_INSTANCE_NULL)
, m_sdskv_client(SDSKV_CLIENT_NULL)
, m_chi_sdskv(nullptr)
, m_end() {}
......@@ -60,8 +54,9 @@ class DataStore::Impl {
throw Exception("Could not initialized Margo");
}
// initialize SDSKV client
ret = sdskv_client_init(m_mid, &m_sdskv_client);
if(ret != SDSKV_SUCCESS) {
try {
m_sdskv_client = sdskv::client(m_mid);
} catch(...) {
cleanup();
throw Exception("Could not create SDSKV client");
}
......@@ -83,44 +78,20 @@ class DataStore::Impl {
}
// get the number of providers
uint16_t num_providers = it->second.as<uint16_t>();
sdskv_provider_handle_t ph;
for(uint16_t provider_id = 0 ; provider_id < num_providers; provider_id++) {
ret = sdskv_provider_handle_create(m_sdskv_client, addr, provider_id, &ph);
if(ret != SDSKV_SUCCESS) {
cleanup();
throw Exception("sdskv_provider_handle_create failed");
}
size_t db_count = 256;
ret = sdskv_count_databases(ph, &db_count);
if(ret != SDSKV_SUCCESS) {
sdskv_provider_handle_release(ph);
std::vector<sdskv::database> dbs;
try {
sdskv::provider_handle ph(m_sdskv_client, addr, provider_id);
dbs = m_sdskv_client.open(ph);
} catch(...) {
cleanup();
throw Exception("sdskv_count_databases failed");
}
std::cerr << "Found " << db_count << " databases" << std::endl;
if(db_count == 0) {
if(dbs.size() == 0) {
continue;
}
std::vector<sdskv_database_id_t> db_ids(db_count);
std::vector<char*> db_names(db_count);
ret = sdskv_list_databases(ph, &db_count, db_names.data(), db_ids.data());
if(ret != SDSKV_SUCCESS) {
sdskv_provider_handle_release(ph);
cleanup();
throw Exception("sdskv_list_databases failed");
}
std::cout << "db_count is now " << db_count << std::endl;
unsigned i = 0;
for(auto id : db_ids) {
std::cout << "Database: " << id << " " << db_names[i] << std::endl;
database db;
sdskv_provider_handle_ref_incr(ph);
db.m_sdskv_ph = ph;
db.m_sdskv_db = id;
for(auto& db : dbs)
m_databases.push_back(db);
i += 1;
}
sdskv_provider_handle_release(ph);
}
}
// initialize ch-placement for the SDSKV providers
......@@ -128,10 +99,8 @@ class DataStore::Impl {
}
void cleanup() {
for(const auto& db : m_databases) {
sdskv_provider_handle_release(db.m_sdskv_ph);
}
sdskv_client_finalize(m_sdskv_client);
m_databases.clear();
m_sdskv_client = sdskv::client();
if(m_chi_sdskv)
ch_placement_finalize(m_chi_sdskv);
for(auto& addr : m_addrs) {
......@@ -181,46 +150,63 @@ class DataStore::Impl {
}
}
static inline std::string buildKey(
uint8_t level,
const std::string& containerName,
const std::string& objectName) {
size_t c = 1 + objectName.size();
if(!containerName.empty()) c += containerName.size() + 1;
std::string result(c,'\0');
result[0] = level;
if(!containerName.empty()) {
std::memcpy(&result[1], containerName.data(), containerName.size());
size_t x = 1+containerName.size();
result[x] = '/';
std::memcpy(&result[x+1], objectName.data(), objectName.size());
} else {
std::memcpy(&result[1], objectName.data(), objectName.size());
}
return result;
}
public:
bool load(uint8_t level, const std::string& containerName,
const std::string& objectName, std::vector<char>& data) const {
int ret;
// build full name
std::stringstream ss;
if(!containerName.empty())
ss << containerName << "/";
ss << objectName;
// build key
auto key = buildKey(level, containerName, objectName);
// hash the name to get the provider id
long unsigned sdskv_provider_idx = 0;
long unsigned sdskv_db_idx = 0;
uint64_t name_hash;
if(level != 0) {
name_hash = std::hash<std::string>()(containerName);
} else {
// use the complete name for final objects (level 0)
name_hash = std::hash<std::string>()(ss.str());
name_hash = std::hash<std::string>()(key);
}
ch_placement_find_closest(m_chi_sdskv, name_hash, 1, &sdskv_provider_idx);
ch_placement_find_closest(m_chi_sdskv, name_hash, 1, &sdskv_db_idx);
// make corresponding datastore entry
DataStoreEntryPtr entry = make_datastore_entry(level, ss.str());
auto& db = m_databases[sdskv_provider_idx];
auto sdskv_ph = db.m_sdskv_ph;
auto db_id = db.m_sdskv_db;
auto& db = m_databases[sdskv_db_idx];
// read the value
// find the size of the value, as a way to check if the key exists
// XXX optimization: instead of getting the size, we could try getting
// the data with a certain size and retry with the right size if it doesn't work
hg_size_t vsize;
ret = sdskv_length(sdskv_ph, db_id, entry->raw(), entry->length(), &vsize);
if(ret == SDSKV_ERR_UNKNOWN_KEY) {
try {
vsize = db.length(key);
} catch(sdskv::exception& ex) {
if(ex.error() == SDSKV_ERR_UNKNOWN_KEY)
return false;
}
if(ret != SDSKV_SUCCESS) {
throw Exception("Error occured when calling sdskv_length");
else
throw Exception("Error occured when calling sdskv::database::length");
}
data.resize(vsize);
ret = sdskv_get(sdskv_ph, db_id, entry->raw(), entry->length(), data.data(), &vsize);
if(ret != SDSKV_SUCCESS) {
throw Exception("Error occured when calling sdskv_get");
try {
db.get(key, data);
} catch(sdskv::exception& ex) {
throw Exception("Error occured when calling sdskv::database::get");
}
return true;
}
......@@ -228,38 +214,34 @@ class DataStore::Impl {
ProductID store(uint8_t level, const std::string& containerName,
const std::string& objectName, const std::vector<char>& data) {
// build full name
std::stringstream ss;
if(!containerName.empty())
ss << containerName << "/";
ss << objectName;
auto key = buildKey(level, containerName, objectName);
// Create the product id
ProductID product_id(level, containerName, objectName);
// hash the name to get the provider id
long unsigned sdskv_provider_idx = 0;
long unsigned sdskv_db_idx = 0;
uint64_t name_hash;
if(level != 0) {
name_hash = std::hash<std::string>()(containerName);
} else {
// use the complete name for final objects (level 0)
name_hash = std::hash<std::string>()(ss.str());
}
ch_placement_find_closest(m_chi_sdskv, name_hash, 1, &sdskv_provider_idx);
// make corresponding datastore entry key
DataStoreEntryPtr entry = make_datastore_entry(level, ss.str());
const auto& sdskv_info = m_databases[sdskv_provider_idx];
auto sdskv_ph = sdskv_info.m_sdskv_ph;
auto db_id = sdskv_info.m_sdskv_db;
// check if the key exists
hg_size_t vsize;
int ret = sdskv_length(sdskv_ph, db_id, entry->raw(), entry->length(), &vsize);
if(ret == HG_SUCCESS) return ProductID(); // key already exists
if(ret != SDSKV_ERR_UNKNOWN_KEY) { // there was a problem with sdskv
throw Exception("Could not check if key exists in SDSKV (sdskv_length error)");
name_hash = std::hash<std::string>()(key);
}
// if it's not a last-level data entry (data product), store in sdskeyval
ret = sdskv_put(sdskv_ph, db_id, entry->raw(), entry->length(), data.data(), data.size());
if(ret != SDSKV_SUCCESS) {
throw Exception("Could not put key/value pair in SDSKV (sdskv_put error)");
ch_placement_find_closest(m_chi_sdskv, name_hash, 1, &sdskv_db_idx);
const auto& db = m_databases[sdskv_db_idx];
// check if the key exists
bool key_exists;
try {
key_exists = db.exists(key);
std::cerr << "In store(), key_exists = " << key_exists << " for key = " << key << std::endl;
} catch(sdskv::exception& ex) {
throw Exception("Could not check if key exists in SDSKV (sdskv::database::exists error)");
}
if(key_exists) return ProductID();
try {
db.put(key, data);
} catch(sdskv::exception& ex) {
throw Exception("Could not put key/value pair in SDSKV (sdskv::database::put error)");
}
return product_id;
}
......@@ -269,63 +251,35 @@ class DataStore::Impl {
std::vector<std::string>& keys, size_t maxKeys) const {
int ret;
if(level == 0) return 0; // cannot iterate at object level
// build full name from lower bound key
std::stringstream ss;
if(!containerName.empty())
ss << containerName << "/";
ss << lower;
// hash the name to get the provider id
long unsigned provider_idx = 0;
long unsigned db_idx = 0;
uint64_t h = std::hash<std::string>()(containerName);
ch_placement_find_closest(m_chi_sdskv, h, 1, &provider_idx);
ch_placement_find_closest(m_chi_sdskv, h, 1, &db_idx);
// make an entry for the lower bound
DataStoreEntryPtr lb_entry = make_datastore_entry(level, ss.str());
// create data structures to receive keys
std::vector<DataStoreEntryPtr> keys_ent;
std::vector<void*> keys_ptr(maxKeys);
std::vector<hg_size_t> keys_len(maxKeys);
for(unsigned i=0; i < maxKeys; i++) {
keys_ent.push_back(make_datastore_entry(level, 1024));
keys_ptr[i] = keys_ent[i]->raw();
keys_len[i] = sizeof(DataStoreEntry) + 1024;
}
auto lb_entry = buildKey(level, containerName, lower);
// get provider and database
const auto& sdskv_info = m_databases[provider_idx];
auto ph = sdskv_info.m_sdskv_ph;
auto db_id = sdskv_info.m_sdskv_db;
// issue an sdskv_list_keys
hg_size_t max_keys = maxKeys;
ret = sdskv_list_keys(ph, db_id, lb_entry->raw(), lb_entry->length(),
keys_ptr.data(), keys_len.data(), &max_keys);
if(ret != HG_SUCCESS) {
throw Exception("Error occured when calling sdskv_list_keys");
}
unsigned i = max_keys - 1;
if(max_keys == 0) return 0;
// remove keys that don't have the same level or the same prefix
std::string prefix = containerName + "/";
keys.resize(0);
for(unsigned i = 0; i < max_keys; i++) {
if(keys_ent[i]->m_level != level) {
max_keys = i;
break;
}
if(!containerName.empty()) {
size_t lenpre = prefix.size();
size_t lenstr = strlen(keys_ent[i]->m_fullname);
if(lenstr < lenpre) {
max_keys = i;
break;
}
if(strncmp(prefix.c_str(), keys_ent[i]->m_fullname, lenpre) != 0) {
max_keys = i;
break;
const auto& db = m_databases[db_idx];
// ignore keys that don't have the same level or the same prefix
std::string prefix(2+containerName.size(), '\0');
prefix[0] = level;
if(containerName.size() != 0) {
std::memcpy(&prefix[1], containerName.data(), containerName.size());
prefix[prefix.size()-1] = '/';
} else {
prefix.resize(1);
}
// issue an sdskv_list_keys
std::vector<std::string> entries(maxKeys);
try {
db.list_keys(lb_entry, prefix, entries);
} catch(...) {
throw Exception("Error occured when calling sdskv::database::list_keys");
}
keys.push_back(keys_ent[i]->m_fullname);
keys.resize(0);
for(const auto& entry : entries) {
keys.emplace_back(&entry[1], entry.size()-1);
}
// set the resulting keys
return max_keys;
return keys.size();
}
};
......
......@@ -10,6 +10,7 @@ int main(int argc, char* argv[])
{
if(argc != 2) return 1;
sleep(1);
// Create the datastore
datastore = new hepnos::DataStore(argv[1]);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment