file_backed_key_set.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Copyright [2021] JD.com, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef __USE_FILE_OFFSET64
  17. #define __USE_FILE_OFFSET64
  18. #endif
  19. #ifndef __USE_LARGEFILE64
  20. #define __USE_LARGEFILE64
  21. #endif
  22. #include <unistd.h>
  23. #include <sys/types.h>
  24. #include <sys/mman.h>
  25. #include <sys/stat.h>
  26. #include <sys/fcntl.h>
  27. #include <cstring>
  28. #include <cassert>
  29. #include <cstdlib>
  30. #include "algorithm/new_hash.h"
  31. #include "log/log.h"
  32. #include "file_backed_key_set.h"
  33. FileBackedKeySet::hash_node_allocator::~hash_node_allocator()
  34. {
  35. reset();
  36. }
  37. void FileBackedKeySet::hash_node_allocator::reset()
  38. {
  39. for (std::vector<char *>::iterator iter = m_buffs.begin();
  40. iter != m_buffs.end(); ++iter) {
  41. ::free(*iter);
  42. }
  43. m_buffs.clear();
  44. m_freeNode = 0;
  45. }
  46. FileBackedKeySet::hash_node *FileBackedKeySet::hash_node_allocator::alloc()
  47. {
  48. if (!m_freeNode) {
  49. FileBackedKeySet::hash_node *nodes =
  50. (hash_node *)calloc(GROW_COUNT, sizeof(hash_node));
  51. FileBackedKeySet::hash_node *n = nodes;
  52. for (int i = 0; i < GROW_COUNT - 1; ++i) {
  53. n->next = n + 1;
  54. ++n;
  55. }
  56. m_freeNode = nodes;
  57. m_buffs.push_back((char *)nodes);
  58. }
  59. hash_node *rtn = m_freeNode;
  60. m_freeNode = (hash_node *)m_freeNode->next;
  61. return rtn;
  62. }
  63. void FileBackedKeySet::hash_node_allocator::free(hash_node *n)
  64. {
  65. n->next = m_freeNode;
  66. m_freeNode = n;
  67. }
  68. FileBackedKeySet::FileBackedKeySet(const char *file, int keySize)
  69. : m_filePath(file), m_fd(-1), m_keySize(keySize),
  70. m_base((char *)MAP_FAILED), m_buckets(0)
  71. {
  72. }
  73. FileBackedKeySet::~FileBackedKeySet()
  74. {
  75. if (m_fd >= 0) {
  76. if (m_base != MAP_FAILED)
  77. munmap(m_base, get_meta_info()->size);
  78. close(m_fd);
  79. }
  80. if (m_buckets)
  81. free(m_buckets);
  82. }
  83. int FileBackedKeySet::Open()
  84. {
  85. assert(m_fd < 0);
  86. assert(m_base == MAP_FAILED);
  87. m_fd = open(m_filePath.c_str(), O_RDWR | O_CREAT | O_LARGEFILE, 0644);
  88. if (m_fd < 0) {
  89. log4cplus_error("open %s failed, %m", m_filePath.c_str());
  90. return -1;
  91. }
  92. //discard all content if any
  93. ftruncate(m_fd, 0);
  94. ftruncate(m_fd, INIT_FILE_SIZE);
  95. m_base = (char *)mmap(NULL, INIT_FILE_SIZE, PROT_READ | PROT_WRITE,
  96. MAP_SHARED, m_fd, 0);
  97. if (m_base == MAP_FAILED) {
  98. log4cplus_error("mmap failed, %m");
  99. close(m_fd);
  100. m_fd = -1;
  101. return -1;
  102. }
  103. meta_info *m = get_meta_info();
  104. m->size = INIT_FILE_SIZE;
  105. m->writePos = sizeof(meta_info);
  106. m_buckets = (hash_node **)calloc(BUCKET_SIZE, sizeof(hash_node *));
  107. return 0;
  108. }
  109. int FileBackedKeySet::Load()
  110. {
  111. assert(m_fd < 0);
  112. assert(m_base == MAP_FAILED);
  113. m_fd = open(m_filePath.c_str(), O_RDWR | O_LARGEFILE);
  114. if (m_fd < 0) {
  115. log4cplus_error("open %s failed, %m", m_filePath.c_str());
  116. return -1;
  117. }
  118. struct stat64 st;
  119. int rtn = fstat64(m_fd, &st);
  120. if (rtn < 0) {
  121. log4cplus_error("fstat64 failed, %m");
  122. close(m_fd);
  123. m_fd = -1;
  124. return -1;
  125. }
  126. m_base = (char *)mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
  127. MAP_SHARED, m_fd, 0);
  128. if (m_base == (char *)MAP_FAILED) {
  129. log4cplus_error("mmap failed, %m");
  130. close(m_fd);
  131. m_fd = -1;
  132. return -1;
  133. }
  134. m_buckets = (hash_node **)calloc(BUCKET_SIZE, sizeof(hash_node *));
  135. char *start = m_base + sizeof(meta_info);
  136. char *end = m_base + get_meta_info()->writePos;
  137. //variable key size
  138. if (m_keySize == 0) {
  139. while (start < end) {
  140. int keyLen = *(unsigned char *)start + 1;
  141. insert_to_set(start + 1, keyLen + 1);
  142. start += keyLen + 1 + 1;
  143. }
  144. } else {
  145. while (start < end) {
  146. insert_to_set(start + 1, m_keySize);
  147. start += m_keySize + 1;
  148. }
  149. }
  150. return 0;
  151. }
  152. int FileBackedKeySet::do_insert(const char *key)
  153. {
  154. if (Contains(key, false))
  155. return 0;
  156. int keyLen = m_keySize == 0 ? (*(unsigned char *)key) + 1 : m_keySize;
  157. char *k = insert_to_file(key, keyLen);
  158. if (!k) //remap failed?
  159. return -1;
  160. insert_to_set(k, keyLen);
  161. return 0;
  162. }
  163. bool FileBackedKeySet::Contains(const char *key, bool checkStatus)
  164. {
  165. int keyLen = m_keySize == 0 ? (*(unsigned char *)key) + 1 : m_keySize;
  166. uint32_t hash = new_hash(key, keyLen) % BUCKET_SIZE;
  167. hash_node *n = m_buckets[hash];
  168. while (n) {
  169. char *k = m_base + n->offset;
  170. if (memcmp(key, k, keyLen) == 0) {
  171. if ((checkStatus == true &&
  172. *(k - 1) == MIGRATE_SUCCESS) ||
  173. checkStatus == false)
  174. return true;
  175. break;
  176. }
  177. n = n->next;
  178. }
  179. return false;
  180. }
  181. bool FileBackedKeySet::is_migrating(const char *key)
  182. {
  183. int keyLen = m_keySize == 0 ? (*(unsigned char *)key) + 1 : m_keySize;
  184. uint32_t hash = new_hash(key, keyLen) % BUCKET_SIZE;
  185. hash_node *n = m_buckets[hash];
  186. while (n) {
  187. char *k = m_base + n->offset;
  188. if (memcmp(key, k, keyLen) == 0) {
  189. if (*(k - 1) == MIGRATE_START)
  190. return true;
  191. break;
  192. }
  193. n = n->next;
  194. }
  195. // key not found
  196. return false;
  197. }
  198. int FileBackedKeySet::Migrated(const char *key)
  199. {
  200. int keyLen = m_keySize == 0 ? (*(unsigned char *)key) + 1 : m_keySize;
  201. uint32_t hash = new_hash(key, keyLen) % BUCKET_SIZE;
  202. hash_node *n = m_buckets[hash];
  203. while (n) {
  204. char *k = m_base + n->offset;
  205. if (memcmp(key, k, keyLen) == 0) {
  206. *(k - 1) = MIGRATE_SUCCESS;
  207. return 0;
  208. }
  209. n = n->next;
  210. }
  211. // key not found
  212. return -1;
  213. }
  214. void FileBackedKeySet::insert_to_set(const char *key, int len)
  215. {
  216. uint32_t hash = new_hash(key, len) % BUCKET_SIZE;
  217. hash_node *n = m_allocator.alloc();
  218. n->next = m_buckets[hash];
  219. n->offset = key - m_base;
  220. m_buckets[hash] = n;
  221. }
  222. char *FileBackedKeySet::insert_to_file(const char *key, int len)
  223. {
  224. meta_info *m = get_meta_info();
  225. if (m->writePos + len + 1 > m->size) {
  226. uintptr_t new_size = m->size + GROW_FILE_SIZE;
  227. if (ftruncate(m_fd, new_size) < 0) {
  228. log4cplus_error("grow file to %p failed, %m",
  229. (void *)new_size);
  230. return NULL;
  231. }
  232. char *base = (char *)mremap(m_base, m->size, new_size,
  233. MREMAP_MAYMOVE);
  234. if (base == MAP_FAILED) {
  235. log4cplus_error("mremap failed, %m");
  236. return NULL;
  237. }
  238. m_base = base;
  239. m = get_meta_info();
  240. m->size = new_size;
  241. }
  242. char *writePos = m_base + m->writePos;
  243. *writePos = MIGRATE_START;
  244. ++writePos;
  245. memcpy(writePos, key, len);
  246. m->writePos += len + 1;
  247. return writePos;
  248. }
  249. void FileBackedKeySet::Clear()
  250. {
  251. if (m_fd >= 0) {
  252. free(m_buckets);
  253. m_allocator.reset();
  254. munmap(m_base, get_meta_info()->size);
  255. close(m_fd);
  256. m_buckets = 0;
  257. m_base = (char *)MAP_FAILED;
  258. m_fd = -1;
  259. unlink(m_filePath.c_str());
  260. }
  261. }