PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/samba-3.5.6/source3/lib/memcache.c

https://github.com/theuni/XBMC-deps
C | 436 lines | 317 code | 86 blank | 33 comment | 87 complexity | 5bcd4c67f5e2eeb7c171ecd484154c7a MD5 | raw file
  1. /*
  2. Unix SMB/CIFS implementation.
  3. In-memory cache
  4. Copyright (C) Volker Lendecke 2007
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "memcache.h"
  17. #include "../lib/util/rbtree.h"
  18. static struct memcache *global_cache;
  19. struct memcache_element {
  20. struct rb_node rb_node;
  21. struct memcache_element *prev, *next;
  22. size_t keylength, valuelength;
  23. uint8 n; /* This is really an enum, but save memory */
  24. char data[1]; /* placeholder for offsetof */
  25. };
  26. struct memcache {
  27. struct memcache_element *mru, *lru;
  28. struct rb_root tree;
  29. size_t size;
  30. size_t max_size;
  31. };
  32. static void memcache_element_parse(struct memcache_element *e,
  33. DATA_BLOB *key, DATA_BLOB *value);
  34. static bool memcache_is_talloc(enum memcache_number n)
  35. {
  36. bool result;
  37. switch (n) {
  38. case GETPWNAM_CACHE:
  39. case PDB_GETPWSID_CACHE:
  40. case SINGLETON_CACHE_TALLOC:
  41. result = true;
  42. break;
  43. default:
  44. result = false;
  45. break;
  46. }
  47. return result;
  48. }
  49. static int memcache_destructor(struct memcache *cache) {
  50. struct memcache_element *e, *next;
  51. for (e = cache->mru; e != NULL; e = next) {
  52. next = e->next;
  53. SAFE_FREE(e);
  54. }
  55. return 0;
  56. }
  57. struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size)
  58. {
  59. struct memcache *result;
  60. result = TALLOC_ZERO_P(mem_ctx, struct memcache);
  61. if (result == NULL) {
  62. return NULL;
  63. }
  64. result->max_size = max_size;
  65. talloc_set_destructor(result, memcache_destructor);
  66. return result;
  67. }
  68. void memcache_set_global(struct memcache *cache)
  69. {
  70. TALLOC_FREE(global_cache);
  71. global_cache = cache;
  72. }
  73. static struct memcache_element *memcache_node2elem(struct rb_node *node)
  74. {
  75. return (struct memcache_element *)
  76. ((char *)node - offsetof(struct memcache_element, rb_node));
  77. }
  78. static void memcache_element_parse(struct memcache_element *e,
  79. DATA_BLOB *key, DATA_BLOB *value)
  80. {
  81. key->data = ((uint8 *)e) + offsetof(struct memcache_element, data);
  82. key->length = e->keylength;
  83. value->data = key->data + e->keylength;
  84. value->length = e->valuelength;
  85. }
  86. static size_t memcache_element_size(size_t key_length, size_t value_length)
  87. {
  88. return sizeof(struct memcache_element) - 1 + key_length + value_length;
  89. }
  90. static int memcache_compare(struct memcache_element *e, enum memcache_number n,
  91. DATA_BLOB key)
  92. {
  93. DATA_BLOB this_key, this_value;
  94. if ((int)e->n < (int)n) return 1;
  95. if ((int)e->n > (int)n) return -1;
  96. if (e->keylength < key.length) return 1;
  97. if (e->keylength > key.length) return -1;
  98. memcache_element_parse(e, &this_key, &this_value);
  99. return memcmp(this_key.data, key.data, key.length);
  100. }
  101. static struct memcache_element *memcache_find(
  102. struct memcache *cache, enum memcache_number n, DATA_BLOB key)
  103. {
  104. struct rb_node *node;
  105. node = cache->tree.rb_node;
  106. while (node != NULL) {
  107. struct memcache_element *elem = memcache_node2elem(node);
  108. int cmp;
  109. cmp = memcache_compare(elem, n, key);
  110. if (cmp == 0) {
  111. return elem;
  112. }
  113. node = (cmp < 0) ? node->rb_left : node->rb_right;
  114. }
  115. return NULL;
  116. }
  117. bool memcache_lookup(struct memcache *cache, enum memcache_number n,
  118. DATA_BLOB key, DATA_BLOB *value)
  119. {
  120. struct memcache_element *e;
  121. if (cache == NULL) {
  122. cache = global_cache;
  123. }
  124. if (cache == NULL) {
  125. return false;
  126. }
  127. e = memcache_find(cache, n, key);
  128. if (e == NULL) {
  129. return false;
  130. }
  131. if (cache->size != 0) {
  132. /*
  133. * Do LRU promotion only when we will ever shrink
  134. */
  135. if (e == cache->lru) {
  136. cache->lru = e->prev;
  137. }
  138. DLIST_PROMOTE(cache->mru, e);
  139. if (cache->mru == NULL) {
  140. cache->mru = e;
  141. }
  142. }
  143. memcache_element_parse(e, &key, value);
  144. return true;
  145. }
  146. void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n,
  147. DATA_BLOB key)
  148. {
  149. DATA_BLOB value;
  150. void *result;
  151. if (!memcache_lookup(cache, n, key, &value)) {
  152. return NULL;
  153. }
  154. if (value.length != sizeof(result)) {
  155. return NULL;
  156. }
  157. memcpy(&result, value.data, sizeof(result));
  158. return result;
  159. }
  160. static void memcache_delete_element(struct memcache *cache,
  161. struct memcache_element *e)
  162. {
  163. rb_erase(&e->rb_node, &cache->tree);
  164. if (e == cache->lru) {
  165. cache->lru = e->prev;
  166. }
  167. DLIST_REMOVE(cache->mru, e);
  168. if (memcache_is_talloc(e->n)) {
  169. DATA_BLOB cache_key, cache_value;
  170. void *ptr;
  171. memcache_element_parse(e, &cache_key, &cache_value);
  172. SMB_ASSERT(cache_value.length == sizeof(ptr));
  173. memcpy(&ptr, cache_value.data, sizeof(ptr));
  174. TALLOC_FREE(ptr);
  175. }
  176. cache->size -= memcache_element_size(e->keylength, e->valuelength);
  177. SAFE_FREE(e);
  178. }
  179. static void memcache_trim(struct memcache *cache)
  180. {
  181. if (cache->max_size == 0) {
  182. return;
  183. }
  184. while ((cache->size > cache->max_size) && (cache->lru != NULL)) {
  185. memcache_delete_element(cache, cache->lru);
  186. }
  187. }
  188. void memcache_delete(struct memcache *cache, enum memcache_number n,
  189. DATA_BLOB key)
  190. {
  191. struct memcache_element *e;
  192. if (cache == NULL) {
  193. cache = global_cache;
  194. }
  195. if (cache == NULL) {
  196. return;
  197. }
  198. e = memcache_find(cache, n, key);
  199. if (e == NULL) {
  200. return;
  201. }
  202. memcache_delete_element(cache, e);
  203. }
  204. void memcache_add(struct memcache *cache, enum memcache_number n,
  205. DATA_BLOB key, DATA_BLOB value)
  206. {
  207. struct memcache_element *e;
  208. struct rb_node **p;
  209. struct rb_node *parent;
  210. DATA_BLOB cache_key, cache_value;
  211. size_t element_size;
  212. if (cache == NULL) {
  213. cache = global_cache;
  214. }
  215. if (cache == NULL) {
  216. return;
  217. }
  218. if (key.length == 0) {
  219. return;
  220. }
  221. e = memcache_find(cache, n, key);
  222. if (e != NULL) {
  223. memcache_element_parse(e, &cache_key, &cache_value);
  224. if (value.length <= cache_value.length) {
  225. if (memcache_is_talloc(e->n)) {
  226. void *ptr;
  227. SMB_ASSERT(cache_value.length == sizeof(ptr));
  228. memcpy(&ptr, cache_value.data, sizeof(ptr));
  229. TALLOC_FREE(ptr);
  230. }
  231. /*
  232. * We can reuse the existing record
  233. */
  234. memcpy(cache_value.data, value.data, value.length);
  235. e->valuelength = value.length;
  236. return;
  237. }
  238. memcache_delete_element(cache, e);
  239. }
  240. element_size = memcache_element_size(key.length, value.length);
  241. e = (struct memcache_element *)SMB_MALLOC(element_size);
  242. if (e == NULL) {
  243. DEBUG(0, ("malloc failed\n"));
  244. return;
  245. }
  246. e->n = n;
  247. e->keylength = key.length;
  248. e->valuelength = value.length;
  249. memcache_element_parse(e, &cache_key, &cache_value);
  250. memcpy(cache_key.data, key.data, key.length);
  251. memcpy(cache_value.data, value.data, value.length);
  252. parent = NULL;
  253. p = &cache->tree.rb_node;
  254. while (*p) {
  255. struct memcache_element *elem = memcache_node2elem(*p);
  256. int cmp;
  257. parent = (*p);
  258. cmp = memcache_compare(elem, n, key);
  259. p = (cmp < 0) ? &(*p)->rb_left : &(*p)->rb_right;
  260. }
  261. rb_link_node(&e->rb_node, parent, p);
  262. rb_insert_color(&e->rb_node, &cache->tree);
  263. DLIST_ADD(cache->mru, e);
  264. if (cache->lru == NULL) {
  265. cache->lru = e;
  266. }
  267. cache->size += element_size;
  268. memcache_trim(cache);
  269. }
  270. void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
  271. DATA_BLOB key, void *pptr)
  272. {
  273. void **ptr = (void **)pptr;
  274. void *p;
  275. if (cache == NULL) {
  276. cache = global_cache;
  277. }
  278. if (cache == NULL) {
  279. return;
  280. }
  281. p = talloc_move(cache, ptr);
  282. memcache_add(cache, n, key, data_blob_const(&p, sizeof(p)));
  283. }
  284. void memcache_flush(struct memcache *cache, enum memcache_number n)
  285. {
  286. struct rb_node *node;
  287. if (cache == NULL) {
  288. cache = global_cache;
  289. }
  290. if (cache == NULL) {
  291. return;
  292. }
  293. /*
  294. * Find the smallest element of number n
  295. */
  296. node = cache->tree.rb_node;
  297. if (node == NULL) {
  298. return;
  299. }
  300. /*
  301. * First, find *any* element of number n
  302. */
  303. while (true) {
  304. struct memcache_element *elem = memcache_node2elem(node);
  305. struct rb_node *next;
  306. if ((int)elem->n == (int)n) {
  307. break;
  308. }
  309. if ((int)elem->n < (int)n) {
  310. next = node->rb_right;
  311. }
  312. else {
  313. next = node->rb_left;
  314. }
  315. if (next == NULL) {
  316. break;
  317. }
  318. node = next;
  319. }
  320. if (node == NULL) {
  321. return;
  322. }
  323. /*
  324. * Then, find the leftmost element with number n
  325. */
  326. while (true) {
  327. struct rb_node *prev = rb_prev(node);
  328. struct memcache_element *elem;
  329. if (prev == NULL) {
  330. break;
  331. }
  332. elem = memcache_node2elem(prev);
  333. if ((int)elem->n != (int)n) {
  334. break;
  335. }
  336. node = prev;
  337. }
  338. while (node != NULL) {
  339. struct memcache_element *e = memcache_node2elem(node);
  340. struct rb_node *next = rb_next(node);
  341. if (e->n != n) {
  342. break;
  343. }
  344. memcache_delete_element(cache, e);
  345. node = next;
  346. }
  347. }