25 #ifndef DOZERG_ATOMIC_HASH_TABLE_H_20130812 26 #define DOZERG_ATOMIC_HASH_TABLE_H_20130812 29 #include "tools/debug.hh" 30 #include "impl/atomic_hash_table_impl.hh" 67 template<
typename>
class HashKey =
CHashFn,
68 template<
typename>
class EqualKey = std::equal_to
72 typedef NS_IMPL::CAtomicHashHead __Head;
73 typedef NS_IMPL::CAtomicHashRowInfo __RowInfo;
74 typedef __RowInfo::__Node __Node;
75 typedef std::vector<__RowInfo> __Rows;
76 typedef typename __Rows::iterator __Iter;
77 typedef typename __Rows::const_iterator __CIter;
80 typedef size_t size_type;
81 typedef EqualKey<key_type> key_equal;
83 typename COmitCV<key_type>::result_type> hasher;
104 if(__Head::Check(capacity, row)){
105 std::vector<uint32_t> cols;
106 size_t realCapa = tools::PrimesGenerator(capacity, row, cols);
107 if(realCapa >= capacity)
108 return bufSize(row, realCapa,
sizeof(key_type) + alignLen(valueLen));
133 init(buf, sz, capacity, row, valueLen, create);
144 bool init(
char * buf,
size_t sz){
145 return initAux(buf, sz,
false, 0, 0, 0);
166 bool init(
char * buf,
size_t sz,
size_t capacity,
int row,
size_t valueLen,
bool create =
false){
167 valueLen = alignLen(valueLen);
169 return this->create(buf, sz, capacity, row, valueLen);
170 return initAux(buf, sz,
true, capacity, row, valueLen);
185 bool valid()
const{
return (NULL != head_ && !rows_.empty());}
195 int rowSize()
const{
return (head_ ? head_->row() : 0);}
208 size_t capacity()
const{
return (head_ ? head_->realCapa() : 0);}
214 size_t sizeOfRow(
int row)
const{
return rows_[row].used();}
221 for(
int i = 0;i <
rowSize();++i)
230 for(
int i = 0;i <
rowSize();++i)
245 time_t
createTime()
const{
return (head_ ? head_->createTime() : 0);}
252 time_t
updateTime()
const{
return (head_ ? head_->modTime() : 0);}
259 time_t
upgradeTime()
const{
return (head_ ? head_->upgradeTime() : 0);}
267 <<
" head="<<tools::ToStringPtr(head_)<<
'\n';
268 for(
int i = 0;i <
rowSize();++i)
269 oss<<
" row["<<i<<
"]="<<rows_[i].
toString(head_->usedArray())<<
'\n';
286 bool insert(
const key_type & key,
const char * value,
size_t len){
292 if(
sizeof key + len > kValueLenMax)
295 if(!insertAux(key, hasher()(key), value, len))
309 bool insert(
const key_type & key,
const std::string & value){
310 return this->
insert(key, value.c_str(), value.length());
322 bool get(
const key_type & key,
char * value,
size_t & len)
const{
327 const uint32_t hash = hasher()(key);
328 const __Node *
const p = searchNode(hash, key);
332 const size_t realLen = p->len();
333 if(realLen <
sizeof(key_type))
335 size_t cur = readNodes(p, value, len, hash);
339 if(cur +
sizeof(key_type) != realLen)
350 bool get(
const key_type & key, std::string & value)
const{
355 const uint32_t hash = hasher()(key);
356 const __Node *
const p = searchNode(hash, key);
360 const size_t realLen = p->len();
361 if(realLen <
sizeof(key_type))
363 value.resize(realLen -
sizeof(key_type));
365 size_t cur = readNodes(p, &value[0], value.size(), hash);
366 return (cur == value.size());
373 bool has(
const key_type & key)
const{
376 return (NULL != searchNode(hasher()(key), key));
387 bool update(
const key_type & key,
const char * value,
size_t len){
393 if(
sizeof key + len > kValueLenMax)
396 const uint32_t hash = hasher()(key);
397 __Node *
const p = searchNode(hash, key);
399 if(!insertAux(key, hash, value, len))
415 bool update(
const key_type & key,
const std::string & value){
416 return this->
update(key, value.c_str(), value.length());
424 size_t remove(
const key_type & key){
429 const uint32_t hash = hasher()(key);
430 const size_t ret = removeAux(searchNode(hash, key), hash);
442 for(__Iter it = rows_.begin();it != rows_.end();++it)
447 static size_t alignLen(
size_t len){
return (len + 7) / 8 * 8;}
448 static size_t bufSize(
int row,
size_t realCapa,
size_t valueSz){
449 return (__Head::HeadSize(row) + __Node::Offset(realCapa, valueSz));
451 void initRows(
const uint32_t * cols, uint32_t * used){
452 assert(cols && used && head_ && rows_.empty());
453 char * p = head_->dataArray();
454 rows_.reserve(head_->row());
455 for(uint16_t i = 0;i < head_->row();++i)
456 rows_.push_back(__RowInfo(cols[i], &used[i], p, head_->valueSz()));
457 std::sort(rows_.begin(), rows_.end(), std::greater<__RowInfo>());
459 bool create(
char * buf,
size_t sz,
size_t capacity,
int row,
size_t valueLen){
463 if(NULL == buf || sz <
sizeof(__Head))
465 if(!__Head::Check(capacity, row))
467 __Head & head = *
reinterpret_cast<__Head *
>(buf);
468 std::vector<uint32_t> cols;
469 const uint64_t realCapa = tools::PrimesGenerator(capacity, row, cols);
470 if(realCapa < capacity ||
size_t(row) != cols.size())
472 if(sz < bufSize(row, realCapa,
sizeof(key_type) + valueLen))
475 ::memset(buf, 0, __Head::HeadSize(row));
478 head_->init<key_type>(
capacity, valueLen, row, realCapa,
true);
480 uint32_t *
const used = head_->usedArray();
482 uint32_t *
const colp = head_->colsArray();
483 std::sort(cols.begin(), cols.end(), std::greater<uint32_t>());
484 std::copy(cols.begin(), cols.end(), colp);
486 initRows(colp, used);
491 bool initAux(
char * buf,
size_t sz,
bool hasFollowing,
size_t capacity,
int row,
size_t valueLen){
495 if(NULL == buf || sz <
sizeof(__Head))
497 __Head & head = *
reinterpret_cast<__Head *
>(buf);
498 if(!head.check<key_type>())
500 if(hasFollowing && !head.check<key_type>(capacity, valueLen, row))
502 if(sz < bufSize(head.row(), head.realCapa(), head.valueSz()))
504 uint32_t *
const used = head.usedArray();
505 const uint32_t *
const cols = head.colsArray();
506 if(!head.check(cols, used))
510 initRows(cols, used);
513 __Node * allocNode(uint32_t hash){
515 for(__Iter it = rows_.begin();it != rows_.end();++it){
516 __Node *
const p = it->allocNode(hash);
522 void allocNodes(uint32_t hash,
size_t cnt, std::vector<__Node *> & ret){
529 for(
size_t i = 0;i < cnt;++i, h = (h + 1) * (h + 2)){
530 __Node *
const p = allocNode(h);
537 if(fail && !ret.empty()){
542 void deallocNode(__Node * p){
543 if(NULL != p &&
valid())
544 for(__Iter it = rows_.begin();it != rows_.end() && !it->deallocNode(p);++it);
546 void deallocNodes(
const std::vector<__Node *> & nodes){
548 for(std::vector<__Node *>::const_iterator i = nodes.begin();i != nodes.end();++i)
551 const __Node * searchNode(uint32_t hash,
const key_type & key)
const{
554 for(__CIter it = rows_.begin();it != rows_.end();++it){
555 const __Node *
const p = it->searchNode(hash);
556 if(NULL != p && key_equal()(key, p->key<key_type>()))
561 __Node * searchNode(uint32_t hash,
const key_type & key){
564 for(__Iter it = rows_.begin();it != rows_.end();++it){
565 __Node *
const p = it->searchNode(hash);
566 if(NULL != p && key_equal()(key, p->key<key_type>()))
571 size_t readNodes(
const __Node * p,
char * value,
size_t len, uint32_t hash)
const{
573 size_t cur = p->getData<key_type>(value, len, head_->valueSz());
576 for(p = head_->nextNode(p, hash);NULL != p;p = head_->nextNode(p, hash))
577 if(!p->getData(value, cur, len, head_->valueSz()))
581 bool insertAux(
const key_type & key, uint32_t hash,
const char * value,
size_t len){
584 std::vector<__Node *> nodes;
585 allocNodes(hash, head_->nodeCount<key_type>(len), nodes);
589 std::vector<__Node *>::const_iterator i = nodes.begin();
590 size_t cur = (*i)->setData(key, value, len, head_->valueSz());
591 for(++i;i != nodes.end();++i){
596 (*i)->setData(value, cur, len, head_->valueSz());
600 for(std::vector<__Node *>::const_iterator j = i + 1;j != nodes.end();++i, ++j)
601 (*i)->setMetaMid(hash, head_->dataOffset(*j));
602 (*i)->setMetaEnd(hash, value, len);
603 nodes.front()->setFirst();
606 size_t removeAux(__Node * p, uint32_t hash){
609 for(;NULL != p;++cnt){
610 __Node *
const n = head_->nextNode(p, hash);
617 mutable __Rows rows_;
void uninit()
Reset current object.
Definition: atomic_hash_table.hh:177
Definition: to_string.hh:43
time_t upgradeTime() const
Get latest upgrading time of the hash table.
Definition: atomic_hash_table.hh:259
static const size_t kValueLenMax
The maximum size of Key plus Value, i.e. 16MB.
Definition: atomic_hash_table.hh:86
CAtomicHashTable()
Prepare an uninitialized object.
Definition: atomic_hash_table.hh:116
CAtomicHashTable(char *buf, size_t sz, size_t capacity, int row, size_t valueLen, bool create=false)
Attach to or create a hash table in a memory buffer.
Definition: atomic_hash_table.hh:130
std::string toString() const
Get a description of the hash table.
Definition: atomic_hash_table.hh:264
size_t sizeOfRow(int row) const
Get number of key-value pairs in a row.
Definition: atomic_hash_table.hh:214
size_t capacity() const
Get capacity of the hash table.
Definition: atomic_hash_table.hh:208
bool has(const key_type &key) const
Test if a key exists in the hash table.
Definition: atomic_hash_table.hh:373
int rowSize() const
Get number of rows in hash table.
Definition: atomic_hash_table.hh:195
time_t updateTime() const
Get latest updating time of the hash table.
Definition: atomic_hash_table.hh:252
bool update(const key_type &key, const char *value, size_t len)
Update value of a key.
Definition: atomic_hash_table.hh:387
bool insert(const key_type &key, const char *value, size_t len)
Insert a key-value pair into the hash table.
Definition: atomic_hash_table.hh:286
size_t size() const
Get number of key-value pair in the hash table.
Definition: atomic_hash_table.hh:219
bool init(char *buf, size_t sz)
Attach to an existing hash table hosted in a memory buffer.
Definition: atomic_hash_table.hh:144
static size_t CalcBufSize(size_t capacity, int row, size_t valueLen)
Compute memory size needed for a hash table.
Definition: atomic_hash_table.hh:103
bool init(char *buf, size_t sz, size_t capacity, int row, size_t valueLen, bool create=false)
Attach to or create a hash table in a memory buffer.
Definition: atomic_hash_table.hh:166
bool valid() const
Test if current object is initialized.
Definition: atomic_hash_table.hh:185
bool insert(const key_type &key, const std::string &value)
Insert a key-value pair into the hash table.
Definition: atomic_hash_table.hh:309
time_t createTime() const
Get creation time of the hash table.
Definition: atomic_hash_table.hh:245
void clear()
Clear all data in the hash table.
Definition: atomic_hash_table.hh:440
A lock-free hash table that can be used in multi-thread or multi-process programs.
Definition: atomic_hash_table.hh:69
size_t capacityOfRow(int row) const
Get capacity of a row in hash table.
Definition: atomic_hash_table.hh:201
bool update(const key_type &key, const std::string &value)
Update value of a key.
Definition: atomic_hash_table.hh:415
Definition: template.hh:174
bool empty() const
Test if the hash table is empty.
Definition: atomic_hash_table.hh:229
CAtomicHashTable(char *buf, size_t sz)
Attach to an existing hash table hosted in a memory buffer.
Definition: atomic_hash_table.hh:121