#include "sharedobjectdata.h"
#include
#include
#include
#define VO_HEADER_SIZE 16
typedef struct{
NUM ver;
NUM user;
NUM time;
NUM size;
} VoHeader;
typedef struct{
NUM ver;
NUM vo_num;
NUM size;
NUM reserve;
} SoHeader;
const ValueObject &SharedObjectData::get(const std::string &key)
{
std::lock_guard<:mutex> lock(data_mtx_get_);
// for (auto elem : data_)
// {
// // std::cout << elem.first << "\n";
// }
if (data_.find(key) != data_.end())
{
return data_[key];
}
else
{
//printf("Cannot find the key %s\n", key.c_str());
return ValueObject();
}
}
void SharedObjectData::set(const std::string &key, const ValueObject &vo)
{
std::lock_guard<:mutex> lock(data_mtx_set_);
if(key.size()>0){
if( ver_ < vo.ver_){
data_[key] = vo; // update value
ver_ = vo.ver_; // update version
}else{
if(get(key).ver_ <= vo.ver_){
data_[key] = vo;
}
}
// if(get(key).ver_ <= vo.ver_){
// //printf("Set OK!: the version is %d-%d\n", get(key).ver_, vo.ver_);
// data_[key] = vo;
// }else{
// //printf("Set failed!: the version is outdate %d-%d\n", get(key).ver_, vo.ver_);
// }
// {
// if (data_.find(key) != data_.end())
// {
// char tab2[1024];
// strncpy_s(tab2, key.c_str(), sizeof(tab2));
// tab2[sizeof(tab2) - 1] = 0;
// printf("the key %s is found \n", tab2);
// for (auto elem : data_)
// {
// std::cout << elem.first << "\n";
// }
// }
// }
}
}
const std::string SharedObjectData::toStr() const
{
// calculate the size and prepaer the buffer
int sz = sizeof(SoHeader); // header
for(auto & kv: data_){
auto& key = kv.first;
auto& vo = kv.second;
sz += KVObject::size(key,vo)+sizeof(NUM);
}
std::string out(sz,'\0');
char* pOut = (char*) out.data();
// prepare header
SoHeader *pH = (SoHeader*) pOut;
pH->size = sz - sizeof(SoHeader);
pH->ver = ver_;
pH->vo_num = data_.size();
pH->reserve = 0;
pOut += sizeof(SoHeader);
// prepare the kv data
for(auto &kv:data_){
auto kvstr = KVObject::toStr(kv.first,kv.second);
*((NUM*) pOut) = kvstr.size();
memcpy(pOut+sizeof(NUM), kvstr.data(), kvstr.size());
pOut += sizeof(NUM) + kvstr.size();
}
return out;
}
int SharedObjectData::init(const std::string &data)
{
// check the data
const char* pData = data.data();
int N = data.size();
const SoHeader *pH = (SoHeader*) pData;
if(pH->size != N - sizeof(SoHeader) ){
printf("Cannot initial the SharedObjectData with incorrect data!\n");
}
pData += sizeof(SoHeader);
// processing
data_.clear();
ver_ = pH->ver;
int kv_num = pH->vo_num;
int rest_num = pH->size;
//printf("kv_num %d\n", kv_num);
while(rest_num>0 && kv_num > 0){
int len = *((NUM*)pData);
std::string kvstr(pData+sizeof(NUM), len);
std::string k;
ValueObject vo;
if( KVObject::fromStr(kvstr,k,vo) >=0){
set(k,vo);
}
rest_num -= len + sizeof(NUM);
pData += len + sizeof(NUM);
kv_num--;
}
return pH->vo_num - kv_num;
}
void SharedObjectData::p(const std::string fln) const
{
std::ofstream ofs;
if(fln.size()){
ofs.open(fln);
ofs <<"SharedObject ver: " << ver_ <<"\n";
for(auto & kv:data_){
ofs <<"" << kv.first.c_str() << ":" << kv.second.val_<<"\n";
}
}else{
printf( "SharedObject ver: %d\n", ver_);
for(auto & kv:data_){
printf("key: %s val: ", kv.first.c_str());
kv.second.p();
}
}
}
ValueObject::ValueObject(const ValueObject &vo)
{
time_ = vo.time_;
ver_ = vo.ver_;
val_ = vo.val_;
user_ = vo.user_;
}
ValueObject::ValueObject(const std::string &data)
{
fromStr(data);
}
ValueObject::ValueObject(const std::string &val, NUM ver, NUM user, NUM time)
{
val_ = val;
time_ = time;
ver_ = ver;
user_ = user;
}
const std::string ValueObject::toStr() const
{
// prepare data buffer
NUM sz = size();
std::string out(sz,'\0');
// set header
VoHeader* pheader = (VoHeader*) out.data();
pheader->size = val_.size();
pheader->time = time_;
pheader->user = user_;
pheader->ver = ver_;
// set value;
memcpy((char*)out.data() + sizeof(VoHeader), val_.data(), val_.size());
return out;
}
int ValueObject::fromStr(const std::string &data)
{
int N = data.size();
if(N < sizeof(VoHeader)){
printf("Cannot initial ValueObject with incorrent data (1)!");
//throw std::exception("Cannot initial ValueObject with incorrent data (1)!");
return -1;
}
VoHeader * pH = (VoHeader*) data.data();
if(N != pH->size + sizeof(VoHeader)){
printf("Cannot initial ValueObject with incorrent data (2)!");
//throw std::exception("Cannot initial ValueObject with incorrent data (2)!");
return -2;
}
val_ = data.substr(sizeof(VoHeader));
time_ = pH->time;
ver_ = pH->ver;
user_ = pH->user;
return 0;
}
int ValueObject::size() const
{
return val_.size() + sizeof(VoHeader);
}
void ValueObject::p() const
{
printf("time-%d ver-%d user-%d: %s\n", time_,ver_,user_,val_.c_str());
}
std::string KVObject::toStr(const std::string &k, const ValueObject &vo)
{
const int NUM_BYTES = sizeof(NUM);
int sz = KVObject::size(k,vo);
std::string out(sz,0);
char* pData = (char*)out.data();
// copy key
*((NUM*)pData) = k.size();
memcpy(pData+ NUM_BYTES, k.data(), k.size());
pData += k.size() + NUM_BYTES;
// copy VO
*((NUM*)pData) = vo.size();
memcpy(pData + NUM_BYTES, vo.toStr().data(), vo.size());
// return
return out;
}
int KVObject::fromStr(const std::string &data, std::string &key, ValueObject &vo)
{
if(data.size() < sizeof(NUM)+2){
return -1;
}
const char* pData = data.data();
int keysize = *((NUM*) pData);
if(keysize > data.size() - sizeof(NUM)){
return -2;
}
key = data.substr(sizeof(NUM), keysize);
int vosize = *((NUM*)(pData + sizeof(NUM) + keysize));
if(vosize != data.size() - sizeof(NUM)*2 - keysize){
return -3;
}
auto vostr = data.substr(sizeof(NUM)*2+keysize);
ValueObject vo1(vostr);
vo = vo1;
return 0;
}
int KVObject::size(const std::string &k, const ValueObject &vo)
{
const int NUM_BYTES = sizeof(NUM);
return k.size() + vo.size() + 2 * NUM_BYTES;
}