negentropy/cpp/negentropy_wrapper.c

229 lines
8.2 KiB
C
Raw Normal View History

#include <iostream>
2024-02-19 04:55:15 +00:00
#include "negentropy.h"
#include "negentropy/storage/BTreeMem.h"
#include "negentropy_wrapper.h"
//This is a C-wrapper for the C++ library that helps in integrating negentropy with nim code.
//TODO: Do error handling by catching exceptions
2024-03-05 11:27:30 +05:30
void printHexString(std::string_view toPrint){
for (size_t i = 0; i < toPrint.size(); ++i) {
printf("%0hhx", toPrint[i]);
}
printf("\n");
}
2024-02-19 04:55:15 +00:00
void* storage_new(const char* db_path, const char* name){
negentropy::storage::BTreeMem* storage;
/*
auto env = lmdb::env::create();
env.set_max_dbs(64);
env.open(db_path, 0);
lmdb::dbi btreeDbi;
{
auto txn = lmdb::txn::begin(env);
btreeDbi = negentropy::storage::BTreeMem::setupDB(txn, name);
txn.commit();
} */
//TODO: Finish constructor
storage = new negentropy::storage::BTreeMem();
return storage;
}
void* negentropy_new(void* storage, uint64_t frameSizeLimit){
//TODO: Make these typecasts into macros??
negentropy::storage::BTreeMem* lmdbStorage;
//TODO: reinterpret cast is risky, need to use more safe type conversion.
lmdbStorage = reinterpret_cast<negentropy::storage::BTreeMem*>(storage);
Negentropy<negentropy::storage::BTreeMem>* ne;
try{
ne = new Negentropy<negentropy::storage::BTreeMem>(*lmdbStorage, frameSizeLimit);
}catch(negentropy::err e){
//TODO:Find a way to return this error
return NULL;
}
return ne;
}
2024-03-04 16:28:35 +05:30
size_t negentropy_initiate(void* negentropy, buffer* out){
2024-02-19 04:55:15 +00:00
Negentropy<negentropy::storage::BTreeMem>* ngn_inst;
ngn_inst = reinterpret_cast<Negentropy<negentropy::storage::BTreeMem>*>(negentropy);
2024-02-22 16:47:07 +05:30
std::string* output = new std::string();
2024-02-19 04:55:15 +00:00
try {
2024-02-22 16:47:07 +05:30
*output = ngn_inst->initiate();
2024-03-05 11:27:30 +05:30
std::cout << "output of initiate is, len:" << output->size() << ", output:";
printHexString(std::string_view(*output));
2024-02-19 04:55:15 +00:00
} catch(negentropy::err e){
//TODO:Find a way to return this error
2024-03-04 16:28:35 +05:30
return 0;
2024-02-19 04:55:15 +00:00
}
2024-03-04 16:28:35 +05:30
memcpy( out->data, output->c_str() ,output->size());
return output->size();
2024-02-19 04:55:15 +00:00
}
void negentropy_setinitiator(void* negentropy){
Negentropy<negentropy::storage::BTreeMem> *ngn_inst;
ngn_inst = reinterpret_cast<Negentropy<negentropy::storage::BTreeMem>*>(negentropy);
ngn_inst->setInitiator();
}
bool storage_insert(void* storage, uint64_t createdAt, buffer* id){
2024-02-19 04:55:15 +00:00
negentropy::storage::BTreeMem* lmdbStorage;
lmdbStorage = reinterpret_cast<negentropy::storage::BTreeMem*>(storage);
2024-03-04 16:28:35 +05:30
std::string_view data(reinterpret_cast< char const* >(id->data), id->len);
std::cout << "inserting entry in storage, createdAt:" << createdAt << ",id:";
printHexString(data);
2024-02-19 04:55:15 +00:00
//TODO: Error handling. Is it required?
//How does out of memory get handled?
2024-03-04 16:28:35 +05:30
return lmdbStorage->insert(createdAt, data);
2024-02-19 04:55:15 +00:00
}
bool storage_erase(void* storage, uint64_t createdAt, buffer* id){
2024-02-19 04:55:15 +00:00
negentropy::storage::BTreeMem* lmdbStorage;
lmdbStorage = reinterpret_cast<negentropy::storage::BTreeMem*>(storage);
2024-03-04 16:28:35 +05:30
std::string_view data(reinterpret_cast< char const* >(id->data), id->len);
std::cout << "erasing entry from storage, createdAt:" << createdAt << ",id:";
printHexString(data);
2024-02-19 04:55:15 +00:00
//TODO: Error handling
2024-03-04 16:28:35 +05:30
return lmdbStorage->erase(createdAt, data);
2024-02-19 04:55:15 +00:00
}
2024-03-04 16:28:35 +05:30
size_t reconcile(void* negentropy, buffer* query, buffer* output){
2024-02-19 04:55:15 +00:00
Negentropy<negentropy::storage::BTreeMem> *ngn_inst;
ngn_inst = reinterpret_cast<Negentropy<negentropy::storage::BTreeMem>*>(negentropy);
2024-03-04 16:28:35 +05:30
std::string* out = new std::string();
2024-02-19 04:55:15 +00:00
try {
2024-03-04 16:28:35 +05:30
*out = ngn_inst->reconcile(std::string_view(reinterpret_cast< char const* >(query->data), query->len));
2024-03-05 11:27:30 +05:30
std::cout << "reconcile output of reconcile is, len:" << out->size() << ", output:";
printHexString(std::string_view(*out));
2024-02-19 04:55:15 +00:00
} catch(negentropy::err e){
//TODO:Find a way to return this error
2024-03-04 16:28:35 +05:30
return 0;
2024-02-19 04:55:15 +00:00
}
2024-03-04 16:28:35 +05:30
memcpy( output->data, out->c_str() ,out->size());
return out->size();
2024-02-19 04:55:15 +00:00
}
2024-03-05 11:27:30 +05:30
void transform(std::vector<std::string> &from_ids, buffer* to_ids)
{
2024-03-05 11:27:30 +05:30
for (int i=0; i < from_ids.size(); i ++){
to_ids[i].len = from_ids[i].size();
to_ids[i].data = (unsigned char*)from_ids[i].c_str();
}
}
int reconcile_with_ids(void* negentropy, buffer* query,reconcile_cbk cbk, char* outptr){
2024-02-19 04:55:15 +00:00
Negentropy<negentropy::storage::BTreeMem> *ngn_inst;
ngn_inst = reinterpret_cast<Negentropy<negentropy::storage::BTreeMem>*>(negentropy);
2024-03-05 11:27:30 +05:30
std::optional<std::string> out;
std::vector<std::string> haveIds, needIds;
uint64_t have_ids_len, need_ids_len;
buffer* have_ids;
buffer* need_ids;
2024-02-19 04:55:15 +00:00
try {
2024-03-05 11:27:30 +05:30
out = ngn_inst->reconcile(std::string_view(reinterpret_cast< char const* >(query->data), query->len), haveIds, needIds);
2024-03-05 11:27:30 +05:30
have_ids_len = haveIds.size();
need_ids_len = needIds.size();
have_ids = (buffer*)malloc(have_ids_len*sizeof(buffer));
need_ids = (buffer*)malloc(need_ids_len*sizeof(buffer));
2024-03-05 11:27:30 +05:30
std::cout << "have_ids_len:" << have_ids_len << "need_ids_len:" << need_ids_len << std::endl;
2024-03-05 11:27:30 +05:30
transform(haveIds, have_ids);
transform(needIds, need_ids);
2024-02-19 04:55:15 +00:00
} catch(negentropy::err e){
2024-03-05 11:27:30 +05:30
std::cout << "caught error "<< e.what() << std::endl;
//TODO:Find a way to return this error and cleanup partially allocated memory if any
return -1;
2024-02-19 04:55:15 +00:00
}
buffer output = {0,NULL};
2024-03-05 11:27:30 +05:30
if (out) {
output.len = out.value().size();
output.data = (unsigned char*)out.value().c_str();
std::cout << "reconcile_with_ids output of reconcile is, len:" << out.value().size() << ", output:";
printHexString(std::string_view(out.value()));
2024-02-19 04:55:15 +00:00
}
std::cout << "invoking callback" << std::endl;
std::flush(std::cout);
cbk(have_ids, have_ids_len, need_ids, need_ids_len, &output, outptr);
std::cout << "invoked callback" << std::endl;
std::flush(std::cout);
2024-03-05 11:27:30 +05:30
free(have_ids);
free(need_ids);
return 0;
}
void transform_with_alloc(std::vector<std::string> &from_ids, buffer* to_ids)
{
for (int i=0; i < from_ids.size(); i ++){
to_ids[i].data = (unsigned char*) malloc(from_ids[i].size()*sizeof(unsigned char));
to_ids[i].len = from_ids[i].size();
memcpy(to_ids[i].data, from_ids[i].c_str(),to_ids[i].len);
}
}
void reconcile_with_ids_no_cbk(void* negentropy, buffer* query, result* result){
Negentropy<negentropy::storage::BTreeMem> *ngn_inst;
ngn_inst = reinterpret_cast<Negentropy<negentropy::storage::BTreeMem>*>(negentropy);
std::optional<std::string> out;
std::vector<std::string> haveIds, needIds;
try {
out = ngn_inst->reconcile(std::string_view(reinterpret_cast< char const* >(query->data), query->len), haveIds, needIds);
result->have_ids_len = haveIds.size();
result->need_ids_len = needIds.size();
result->have_ids = (buffer*)malloc(result->have_ids_len*sizeof(buffer));
result->need_ids = (buffer*)malloc(result->need_ids_len*sizeof(buffer));
std::cout << "have_ids_len:" << result->have_ids_len << "need_ids_len:" << result->need_ids_len << std::endl;
transform_with_alloc(haveIds, result->have_ids);
transform_with_alloc(needIds, result->need_ids);
} catch(negentropy::err e){
std::cout << "caught error "<< e.what() << std::endl;
//TODO:Find a way to return this error and cleanup partially allocated memory if any
return ;
}
buffer output = {0,NULL};
if (out) {
result->output.len = out.value().size();
result->output.data = (unsigned char*)malloc(out.value().size()*sizeof(unsigned char));
result->output.data = (unsigned char*)out.value().c_str();
std::cout << "reconcile_with_ids output of reconcile is, len:" << out.value().size() << ", output:";
printHexString(std::string_view(out.value()));
}
return ;
}
//Note: This function assumes that all relevant heap memory is alloced and just tries to free
void free_result(result* r){
free((void *) r->output.data);
for (int i = 0; i < r->have_ids_len; i++) {
free((void *) r->have_ids[i].data);
}
free((void *)r->have_ids);
for (int i = 0; i < r->need_ids_len; i++) {
free((void *) r->need_ids[i].data);
}
free((void *)r->need_ids);
}