Mysql implementation local KeyValue Database Cache example _mysql

Source: Internet
Author: User

Key-value Cache There are many, with more memcache, Redis, they are operating in the form of independent services, sometimes in the work of the need to embed a local Key-value cache, of course, there are leveldb, but the feeling is still too heavyweight.

This article implements a super lightweight cache,

1, the implementation of the code requires only 400 lines;

2, high performance, value length at 1K test speed at about 2 million per second

3, the cache is mapped to the file, so there is no malloc, free overhead, as well as the memory leak, memory fragments, etc.

4, if the service is dead, the cache content continues to exist after the reboot;

5, if the cache map to disk files even if the machine hangs, the contents of the cache will still exist, of course, there may be data corruption;

6, to a certain extent, the implementation of the LRU elimination algorithm, the realization of the LRU is not the global only a chain, so can only say that in a certain procedure to achieve;

7, stable, has been used in a number of projects, online deployment of the machine has dozens of units, running a large six months has not been a problem;

8, the general cache key, value is the form of strings, this cache key, value can be class, struct object structure more convenient;

The old rules go directly to code:

Copy Code code as follows:



Template<typename K, TypeName v>


Class HashTable


{


Public


HashTable (const char *tablename, uint32_t Tablelen, uint32_t nodetotal);


Virtual ~hashtable ();





BOOL Add (K &key, V &value)


{


Autolock Autolock (M_mutexlock);





Check is exist


uint32_t nodeId = Getidbykey (key);


if (nodeId!= m_invalidid) return false;





NodeId = Getfreenode ();


if (nodeId = = M_invalidid) return false;





uint32_t hashcode = key. Hashcode ();


Entry *tmpnode = m_entryaddr + nodeId;


Tmpnode->m_key = Key;


Tmpnode->m_code = hashcode;


Tmpnode->m_value = Value;





uint32_t index = hashcode% m_headaddr->m_tablelen;


Addnodetohead (index, NODEID);





return true;


}





BOOL Del (K &key)


{


Autolock Autolock (M_mutexlock);





uint32_t nodeId = Getidbykey (key);


if (nodeId = = M_invalidid) return false;





uint32_t index = key. Hashcode ()% m_headaddr->m_tablelen;





Return Recyclenode (index, NODEID);


}





BOOL Set (K &key, V &value)


{


Autolock Autolock (M_mutexlock);





uint32_t nodeId = Getidbykey (key);


if (nodeId = = M_invalidid) return false;





(M_entryaddr + nodeId)->m_value = Value;





return true;


}





BOOL Get (K &key, V &value)


{


Autolock Autolock (M_mutexlock);





uint32_t nodeId = Getidbykey (key);


if (nodeId = = M_invalidid) return false;





Value = (m_entryaddr + nodeId)->m_value;





return true;


}





BOOL Exist (K &key)


{


Autolock Autolock (M_mutexlock);





uint32_t nodeId = Getidbykey (key);


if (nodeId = = M_invalidid) return false;





return true;


}





uint32_t Count ()


{


Autolock Autolock (M_mutexlock);


Return m_headaddr->m_usedcount;


}





If exist set else add


BOOL Replace (K &key, V &value)


{


Autolock Autolock (M_mutexlock);





if (Exist (key)) return Set (key, value);


else return ADD (key, value);


}





/***********************************************


Lru:when visit a node, move it to head * * *


************************************************/


If no empty place,recycle tail


BOOL Lruadd (k &key, v &value, K &recykey, v &recyvalue, BOOL &recycled)


{


Autolock Autolock (M_mutexlock);





if (Exist (key)) return false;





if (ADD (key, value)) return true;





uint32_t index = key. Hashcode ()% m_headaddr->m_tablelen;


uint32_t tailid = Gettailnodeid (index);





if (Tailid = = M_invalidid) return false;





Entry *tmpnode = m_entryaddr + tailid;


Recykey = tmpnode->m_key;


Recyvalue = tmpnode->m_value;


Recycled = true;





Recyclenode (index, tailid);





Return Add (key, value);


}





BOOL Lruset (K &key, V &value)


{


Autolock Autolock (M_mutexlock);





if (Set (key, value)) return Movetohead (key);


else return false;


}





BOOL Lruget (K &key, V &value)


{


Autolock Autolock (M_mutexlock);





if (key, value) return Movetohead (key);


else return false;


}





If exist set else add; If add failed recycle tail than add


BOOL Lrureplace (k &key, v &value, K &recykey, v &recyvalue, BOOL &recycled)


{


Autolock Autolock (M_mutexlock);





Recycled = false;





if (Exist (key)) return Lruset (key, value);


else return Lruadd (key, value, Recykey, recyvalue, recycled);


}





void Clear ()


{


Autolock Autolock (M_mutexlock);





m_headaddr->m_freebase = 0;


M_headaddr->m_recyclehead = 0;


M_headaddr->m_usedcount = 0;


for (uint32_t i = 0; i < m_headaddr->m_tablelen; ++i)


{


(m_arrayaddr+i)->m_head = M_invalidid;


(m_arrayaddr+i)->m_tail = M_invalidid;


}


}





int Getrowkeys (vector<k> &keys, uint32_t index)


{


Autolock Autolock (M_mutexlock);





if (index >= m_headaddr->m_tablelen) return-1;





Keys.clear ();


Keys.reserve (16);





int count = 0;


Array *tmparray = m_arrayaddr + index;


uint32_t nodeId = tmparray->m_head;


while (NodeId!= m_invalidid)


{


Entry *tmpnode = m_entryaddr + nodeId;


Keys.push_back (Tmpnode->m_key);


NodeId = tmpnode->m_next;


++count;


}





return count;


}





void *padding (uint32_t size)


{


Autolock Autolock (M_mutexlock);





if (Size > m_headsize-sizeof (tablehead)) return NULL;


else return m_headaddr->m_padding;


}





Private


static const uint32_t M_invalidid = 0xFFFFFFFF;


static const uint32_t m_headsize = 1024;


struct Tablehead


{


uint32_t M_tablelen;


uint32_t m_nodetotal;


uint32_t m_freebase;


uint32_t M_recyclehead;


uint32_t M_usedcount;


Char m_tablename[256];


uint32_t M_padding[0];


};





struct Array


{


uint32_t M_head;


uint32_t M_tail;


};





struct Entry


{


V m_value;


K M_key;


uint32_t M_code;


uint32_t M_next;


uint32_t M_prev;


};





size_t M_memsize;


uint8_t *m_memaddr;


Tablehead *m_headaddr;


Array *m_arrayaddr;


Entry *m_entryaddr;





Threadmutex M_mutexlock;





BOOL Movetohead (K &key);


uint32_t Getidbykey (K &key);


void Addnodetohead (uint32_t index, uint32_t nodeId);


BOOL Movenodetohead (uint32_t index, uint32_t nodeId);


BOOL Recyclenode (uint32_t index, uint32_t nodeId);


uint32_t Gettailnodeid (uint32_t index);


uint32_t Getfreenode ();





Disable_copy_and_assign (HashTable);


};





Template<typename K, TypeName v>


Hashtable<k, v>::hashtable (const char *tablename, uint32_t Tablelen, uint32_t nodetotal)


{


Abortassert (tablename!= NULL);





M_memsize = m_headsize + tablelen*sizeof (Array) + nodetotal*sizeof (Entry);


M_memaddr = (uint8_t*) memfile::realloc (tablename, m_memsize);


Abortassert (m_memaddr!= NULL);





M_headaddr = (tablehead*) (M_MEMADDR);


M_arrayaddr = (array*) (m_memaddr + m_headsize);


M_entryaddr = (entry*) (m_memaddr + m_headsize + tablelen*sizeof (Array));





M_headaddr->m_tablelen = Tablelen;


M_headaddr->m_nodetotal = Nodetotal;


strncpy (M_headaddr->m_tablename, tablename, sizeof (m_headaddr->m_tablename));





if (M_headaddr->m_usedcount = = 0)//if the ' I ' init array to invalid ID


{


for (uint32_t i = 0; i < Tablelen; ++i)


{


(m_arrayaddr+i)->m_head = M_invalidid;


(m_arrayaddr+i)->m_tail = M_invalidid;


}





m_headaddr->m_freebase = 0;


M_headaddr->m_recyclehead = 0;


}


}





Template<typename K, TypeName v>


Hashtable<k, V>::~hashtable ()


{


Memfile::release (M_MEMADDR, m_memsize);


}





Template<typename K, TypeName v>


BOOL Hashtable<k, V>::movetohead (K &key)


{


uint32_t nodeId = Getidbykey (key);


uint32_t index = key. Hashcode ()% m_headaddr->m_tablelen;





Return Movenodetohead (index, NODEID);


}





Template<typename K, TypeName v>


uint32_t hashtable<k, V>::getidbykey (K &key)


{


uint32_t hashcode = key. Hashcode ();


uint32_t index = hashcode% m_headaddr->m_tablelen;


Array *tmparray = m_arrayaddr + index;





uint32_t nodeId = tmparray->m_head;


while (NodeId!= m_invalidid)


{


Entry *tmpnode = m_entryaddr + nodeId;


if (Tmpnode->m_code = = Hashcode && key. Equals (Tmpnode->m_key)) break;





NodeId = tmpnode->m_next;


}





return nodeId;


}





Template<typename K, TypeName v>


void Hashtable<k, V>::addnodetohead (uint32_t index, uint32_t nodeId)


{


if (Index >= M_headaddr->m_tablelen | | | nodeId >= m_headaddr->m_nodetotal) return;





Array *tmparray = m_arrayaddr + index;


Entry *tmpnode = m_entryaddr + nodeId;


if (M_invalidid = = Tmparray->m_head)


{


Tmparray->m_head = nodeId;


Tmparray->m_tail = nodeId;


}


Else


{


Tmpnode->m_next = tmparray->m_head;


(M_entryaddr + tmparray->m_head)->m_prev = nodeId;


Tmparray->m_head = nodeId;


}


}





Template<typename K, TypeName v>


BOOL Hashtable<k, V>::movenodetohead (uint32_t index, uint32_t nodeId)


{


if (Index >= M_headaddr->m_tablelen | | | | nodeId >= m_headaddr->m_nodetotal) return false;





Array *tmparray = m_arrayaddr + index;


Entry *tmpnode = m_entryaddr + nodeId;





Already head


if (Tmparray->m_head = = nodeId)


{


return true;


}





uint32_t Nodeprev = tmpnode->m_prev;


uint32_t Nodenext = tmpnode->m_next;


(m_entryaddr+nodeprev)->m_next = Nodenext;


if (Nodenext!= m_invalidid)


{


(m_entryaddr+nodenext)->m_prev = Nodeprev;


}


Else


{


Tmparray->m_tail = Nodeprev;


}





Tmpnode->m_prev = M_invalidid;


Tmpnode->m_next = tmparray->m_head;


(M_entryaddr + tmparray->m_head)->m_prev = nodeId;


Tmparray->m_head = nodeId;





return true;


}





Template<typename K, TypeName v>


BOOL Hashtable<k, V>::recyclenode (uint32_t index, uint32_t nodeId)


{


if (Index >= M_headaddr->m_tablelen | | | | nodeId >= m_headaddr->m_nodetotal) return false;





Array *tmparray = m_arrayaddr + index;


Entry *tmpnode = m_entryaddr + nodeId;





uint32_t Nodeprev = tmpnode->m_prev;


uint32_t Nodenext = tmpnode->m_next;





if (Nodeprev!= m_invalidid)


{


(M_entryaddr + nodeprev)->m_next = Nodenext;


}


Else


{


Tmparray->m_head = Nodenext;


}





if (Nodenext!= m_invalidid)


{


(M_entryaddr + nodenext)->m_prev = Nodeprev;


}


Else


{


Tmparray->m_tail = Nodeprev;


}





(m_entryaddr+nodeid)->m_next = m_headaddr->m_recyclehead;


M_headaddr->m_recyclehead = nodeId;


--(M_headaddr->m_usedcount);





return true;


}





Template<typename K, TypeName v>


uint32_t hashtable<k, V>::gettailnodeid (uint32_t index)


{


if (index >= m_headaddr->m_tablelen) return m_invalidid;





Array *tmparray = m_arrayaddr + index;





Return tmparray->m_tail;


}





Template<typename K, TypeName v>


uint32_t hashtable<k, V>::getfreenode ()


{


uint32_t nodeId = M_invalidid;


if (M_headaddr->m_usedcount < m_headaddr->m_freebase)//get from recycle list


{


NodeId = m_headaddr->m_recyclehead;


M_headaddr->m_recyclehead = (M_entryaddr+nodeid)->m_next;


+ + (M_headaddr->m_usedcount);


}


else if (M_headaddr->m_usedcount < m_headaddr->m_nodetotal)//get from free mem


{


NodeId = m_headaddr->m_freebase;


+ + (m_headaddr->m_freebase);


+ + (M_headaddr->m_usedcount);


}


Else


{


NodeId = M_invalidid;


}





Init node


if (NodeId < m_headaddr->m_nodetotal)


{


Entry *tmpnode = m_entryaddr + nodeId;


memset (tmpnode, 0, sizeof (Entry));





Tmpnode->m_next = M_invalidid;


Tmpnode->m_prev = M_invalidid;


}





return nodeId;


}


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.