identt
StoreTable.hpp
Go to the documentation of this file.
1 
33 #ifndef _IDENTT_STORE_STORE_TABLE_HPP_
34 #define _IDENTT_STORE_STORE_TABLE_HPP_
35 
36 #include <set>
37 #include <google/protobuf/reflection.h>
38 #include <google/protobuf/map.h>
39 #include "StoreLevel.hpp"
40 
41 namespace identt {
42 namespace store {
43 template <class T>
44 class StoreTable : public StoreLevel {
45 public:
46  using StoreLevel::dbpointer;
47  using KeySetT=std::set<KeyTypeE>;
48  using MapT=google::protobuf::Map<uint64_t,T>;
49 
66  StoreTable(dbpointer trydb, const KeyTypeE pkey, const KeySetT ukeys, const KeySetT ikeys)
67  :
68  StoreLevel(trydb),
69  PrimaryKey(pkey),
70  unique_keys(ukeys),
71  index_keys(ikeys)
72  {}
73 
78  virtual ~StoreTable() {}
79 
84  StoreTable() = delete;
85  StoreTable(const StoreTable&) = delete;
86  StoreTable& operator=(const StoreTable&) = delete;
87  // StoreTable(const std::string, const size_t) = delete;
88  // void Initialize(const std::string , const size_t , uint64_t& ,uint64_t& )=delete;
89 
102  bool GetOne(T* record, KeyTypeE keytype)
103  {
104  bool key_found=false;
105  std::string key,value;
106  usemydb::Status s ;
107  // primary key is direct
108  if (keytype==PrimaryKey) {
109  key = GetKey(record,PrimaryKey,false);
110  key_found=true;
111  // check if unique key or index key
112  } else if ( unique_keys.find(keytype)!=unique_keys.end() || index_keys.find(keytype)!=index_keys.end()) {
113  s = getDB()->Get(usemydb::ReadOptions(), GetKey(record,keytype,false), &value);
114  if (s.ok()) {
115  NodeT node;
116  if ( node.ParseFromString(value) ) {
117  record->set_id( node.id() );
118  key = GetKey(record,PrimaryKey,false);
119  key_found=true;
120  }
121  }
122  } else
123  throw identt::BadDataException("Keytype invalid");
124 
125  if (!key_found) {
126  return false;
127  }
128  s = getDB()->Get(usemydb::ReadOptions(), key, &value);
129  if (!s.ok()) {
130  return false;
131  }
132 
133  if (!record->ParseFromString(value))
134  throw identt::BadDataException("Record cannot be parsed");
135 
136  return true;
137  }
138 
139 
161  bool GetMany(T* refer, MapT* records, KeyTypeE keytype, size_t skip, size_t limit)
162  {
163  if (keytype==PrimaryKey) {
164  throw identt::BadCodeException("This cannot be used for primary key");
165  }
166  NodeListT nodes;
167  bool key_found=GetKeysFromIndex(keytype,refer, &nodes,skip,limit);
168  if (!key_found) return false;
169  std::string key,value;
170  usemydb::Status s ;
171  T record;
172 
173  for (size_t i=0; i<nodes.node_size(); ++i) {
174  if (nodes.mutable_node(i)->keytype()!=PrimaryKey)
175  throw identt::BadDataException("Record is bad ");
176  record.set_id( nodes.mutable_node(i)->id() );
177  key = GetKey(&record,PrimaryKey,false);
178  s = getDB()->Get(usemydb::ReadOptions(), key, &value);
179  if (!s.ok())
180  throw identt::BadDataException("Record is missing ");
181  if (!record.ParseFromString(value))
182  throw identt::BadDataException("Record cannot be parsed");
183  (*records)[record.id()]=record;
184  }
185 
186  return true;
187  }
188 
205  void AddTrans(TransactionT* trans, std::string key, std::string& value, bool to_del)
206  {
207  TransItemT* item = trans->add_item();
208  item->set_key(key);
209  if (!to_del) item->set_value(value);
210  item->set_to_del(to_del);
211  }
212 
213 
229  virtual std::string GetKey(T* record, KeyTypeE keytype, bool pre)=0;
230 
246  bool GetSecondaryValue(T* record, KeyTypeE keytype, NodeT* node)
247  {
248  if ( unique_keys.find(keytype)==unique_keys.end() && index_keys.find(keytype)==index_keys.end() )
249  return false;
250  std::string key = GetKey(record,keytype,false);
251  std::string value;
252  usemydb::Status s = getDB()->Get(usemydb::ReadOptions(), key, &value);
253  if (!s.ok()) return false;
254  return node->ParseFromString(value);
255  }
256 
272  bool AddRecord(T* record, TransactionT* trans, bool upsert)
273  {
274 
275  if (record->notfound()) return false; // bad data
276  if (record->id()==0) return false; // bad data
277 
278  T old;
279  old.set_id(record->id());
280  bool old_record_exists = GetOne(&old,PrimaryKey);
281  if (old_record_exists && !upsert) return false; // old data no upsert
282 
283  NodeT node;
284  bool status;
285 
286  // check unique key for clash
287  for (auto& keytype : unique_keys) {
288  status = GetSecondaryValue(record,keytype,&node);
289  if (status && ( record->id() != node.id()) ) return false; // unique key clash
290  }
291 
292  // node record for dump
293  std::string dumpid;
294  node.set_id(record->id());
295  node.set_keytype(PrimaryKey);
296  node.SerializeToString(&dumpid);
297 
298  // check unique keys , delete old and update new , keep if same
299  for (auto& keytype : unique_keys) {
300  std::string u_new = GetKey(record,keytype,false);
301  if (old_record_exists) {
302  std::string u_old = GetKey(&old,keytype,false);
303  if (u_old!=u_new) {
304  AddTrans(trans,u_old,dumpid,true); // dumpid ignored
305  AddTrans(trans,u_new,dumpid,false);
306  }
307  } else {
308  AddTrans(trans,u_new,dumpid,false);
309  }
310  }
311 
312  // check index keys , delete old and update new , keep if same
313  for (auto& keytype : index_keys) {
314  std::string u_new = GetKey(record,keytype,false);
315  if (old_record_exists) {
316  std::string u_old = GetKey(&old,keytype,false);
317  if (u_old!=u_new) {
318  AddTrans(trans,u_old,dumpid,true); // dumpid ignored
319  AddTrans(trans,u_new,dumpid,false);
320  }
321  } else {
322  AddTrans(trans,u_new,dumpid,false);
323  }
324  }
325 
326  // add the record
327  record->SerializeToString(&dumpid);
328  std::string pkey = GetKey(record,PrimaryKey,false);
329  AddTrans(trans,pkey,dumpid,false);
330 
331  return true;
332  }
333 
346  bool DelRecord(T* record, TransactionT* trans)
347  {
348  if (record->notfound()) return false; // bad data
349 
350  // insert record for deletion
351  std::string value;
352  AddTrans(trans,EncodePrimaryKey(PrimaryKey,record->id()),value,true);
353  for (auto& keytype : unique_keys) {
354  AddTrans(trans,GetKey(record,keytype,false),value,true);
355  }
356  for (auto& keytype : index_keys) {
357  AddTrans(trans,GetKey(record,keytype,false),value,true);
358  }
359  return true;
360  }
361 
383  bool GetKeysFromIndex(KeyTypeE keytype, T* record, NodeListT* nodes,size_t skip, size_t limit)
384  {
385  if ( unique_keys.find(keytype)==unique_keys.end() && index_keys.find(keytype)==index_keys.end() )
386  return false;
387  std::string key = GetKey(record,keytype,true);
388  if (key.length() <= IDENTT_KEYID_LEN ) return false;
389  std::shared_ptr<usemydb::Iterator> it(getDB()->NewIterator(usemydb::ReadOptions()));
390  usemydb::Slice start = usemydb::Slice ( key );
391  usemydb::Slice match = usemydb::Slice ( key );
392  uint64_t counter=0;
393  bool at_least_one=false;
394  for (it->Seek(start); it->Valid() && it->key().starts_with(match) ; it->Next()) {
395  if (++counter<=skip) continue; // ignore skip
396  NodeT* node = nodes->add_node();
397  node->ParseFromString(it->value().ToString());
398  at_least_one=true;
399  if (counter==skip+limit) break; // to handle the id==0 this comes here
400  }
401  return at_least_one;
402  }
403 
422  void ScanTable(uint64_t startid, size_t limit, std::function<void(T*)> Func)
423  {
424  std::shared_ptr<usemydb::Iterator> it(getDB()->NewIterator(usemydb::ReadOptions()));
425  std::string keymatch = EncodeKeyType(PrimaryKey);
426  usemydb::Slice match = usemydb::Slice ( keymatch );
427  startid = (startid>0) ? startid : 1;
428  std::string keystart = EncodePrimaryKey(PrimaryKey,startid);
429  usemydb::Slice start = usemydb::Slice ( keystart );
430 
431  uint64_t counter=0;
432  for (it->Seek(start); it->Valid() && it->key().starts_with(match) ; it->Next()) {
433  T record;
434  if (!record.ParseFromString(it->value().ToString()) )
435  throw identt::BadDataException("Record cannot be parsed");
436  Func(&record);
437  if (++counter==limit) break;
438  }
439  }
440 
441 protected:
442  const KeyTypeE PrimaryKey;
443  const KeySetT unique_keys;
444  const KeySetT index_keys;
445 
446 
447 };
448 } // namespace store
449 } // namespace identt
450 #endif /* _IDENTT_STORE_STORE_TABLE_HPP_ */
Definition: StoreLevel.hpp:49
bool DelRecord(T *record, TransactionT *trans)
DelRecord : get delete transaction item.
Definition: StoreTable.hpp:346
bool GetOne(T *record, KeyTypeE keytype)
GetOne: get a record by primary or unique key.
Definition: StoreTable.hpp:102
void AddTrans(TransactionT *trans, std::string key, std::string &value, bool to_del)
AddTrans : add transactions.
Definition: StoreTable.hpp:205
bool GetSecondaryValue(T *record, KeyTypeE keytype, NodeT *node)
GetSecondaryValue: get a secondary key value.
Definition: StoreTable.hpp:246
std::string EncodePrimaryKey(KeyTypeE keytype, ::google::protobuf::uint64 id)
EncodePrimaryKey : make primary key with id only.
Definition: StoreBase.cc:124
Definition: StoreTable.hpp:44
bool GetKeysFromIndex(KeyTypeE keytype, T *record, NodeListT *nodes, size_t skip, size_t limit)
GetKeysFromIndex : get primary keys from secondary.
Definition: StoreTable.hpp:383
StoreTable(dbpointer trydb, const KeyTypeE pkey, const KeySetT ukeys, const KeySetT ikeys)
Constructor.
Definition: StoreTable.hpp:66
Definition: CryptoBase.hpp:49
bool AddRecord(T *record, TransactionT *trans, bool upsert)
AddRecord : get transaction item.
Definition: StoreTable.hpp:272
Definition: BaseUtils.hpp:89
std::string EncodeKeyType(KeyTypeE keytype)
EncodeKeyType : make prefix key with keytype.
Definition: StoreBase.cc:113
virtual ~StoreTable()
Destructor.
Definition: StoreTable.hpp:78
virtual std::string GetKey(T *record, KeyTypeE keytype, bool pre)=0
GetKey: get a key.
StoreTable()=delete
make noncopyable and remove default
dbpointer getDB()
getDB: Get shared pointer to DB
Definition: StoreLevel.cc:155
void ScanTable(uint64_t startid, size_t limit, std::function< void(T *)> Func)
ScanTable : scan by primary key.
Definition: StoreTable.hpp:422
Definition: BaseUtils.hpp:95
bool GetMany(T *refer, MapT *records, KeyTypeE keytype, size_t skip, size_t limit)
GetMany: get all values by non unique key.
Definition: StoreTable.hpp:161