You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
13 KiB

  1. /* cache .c - a LRU cache
  2. *
  3. * Copyright (C) 2004-2010 Gerhard Hring <gh@ghaering.de>
  4. *
  5. * This file is part of pysqlite.
  6. *
  7. * This software is provided 'as-is', without any express or implied
  8. * warranty. In no event will the authors be held liable for any damages
  9. * arising from the use of this software.
  10. *
  11. * Permission is granted to anyone to use this software for any purpose,
  12. * including commercial applications, and to alter it and redistribute it
  13. * freely, subject to the following restrictions:
  14. *
  15. * 1. The origin of this software must not be misrepresented; you must not
  16. * claim that you wrote the original software. If you use this software
  17. * in a product, an acknowledgment in the product documentation would be
  18. * appreciated but is not required.
  19. * 2. Altered source versions must be plainly marked as such, and must not be
  20. * misrepresented as being the original software.
  21. * 3. This notice may not be removed or altered from any source distribution.
  22. */
  23. #include "sqlitecompat.h"
  24. #include "cache.h"
  25. #include <limits.h>
  26. /* only used internally */
  27. pysqlite_Node* pysqlite_new_node(PyObject* key, PyObject* data)
  28. {
  29. pysqlite_Node* node;
  30. node = (pysqlite_Node*) (pysqlite_NodeType.tp_alloc(&pysqlite_NodeType, 0));
  31. if (!node) {
  32. return NULL;
  33. }
  34. Py_INCREF(key);
  35. node->key = key;
  36. Py_INCREF(data);
  37. node->data = data;
  38. node->prev = NULL;
  39. node->next = NULL;
  40. return node;
  41. }
  42. void pysqlite_node_dealloc(pysqlite_Node* self)
  43. {
  44. Py_DECREF(self->key);
  45. Py_DECREF(self->data);
  46. Py_TYPE(self)->tp_free((PyObject*)self);
  47. }
  48. int pysqlite_cache_init(pysqlite_Cache* self, PyObject* args, PyObject* kwargs)
  49. {
  50. PyObject* factory;
  51. int size = 10;
  52. self->factory = NULL;
  53. if (!PyArg_ParseTuple(args, "O|i", &factory, &size)) {
  54. return -1;
  55. }
  56. /* minimum cache size is 5 entries */
  57. if (size < 5) {
  58. size = 5;
  59. }
  60. self->size = size;
  61. self->first = NULL;
  62. self->last = NULL;
  63. self->mapping = PyDict_New();
  64. if (!self->mapping) {
  65. return -1;
  66. }
  67. Py_INCREF(factory);
  68. self->factory = factory;
  69. self->decref_factory = 1;
  70. return 0;
  71. }
  72. void pysqlite_cache_dealloc(pysqlite_Cache* self)
  73. {
  74. pysqlite_Node* node;
  75. pysqlite_Node* delete_node;
  76. if (!self->factory) {
  77. /* constructor failed, just get out of here */
  78. return;
  79. }
  80. /* iterate over all nodes and deallocate them */
  81. node = self->first;
  82. while (node) {
  83. delete_node = node;
  84. node = node->next;
  85. Py_DECREF(delete_node);
  86. }
  87. if (self->decref_factory) {
  88. Py_DECREF(self->factory);
  89. }
  90. Py_DECREF(self->mapping);
  91. Py_TYPE(self)->tp_free((PyObject*)self);
  92. }
  93. PyObject* pysqlite_cache_get(pysqlite_Cache* self, PyObject* args)
  94. {
  95. PyObject* key = args;
  96. pysqlite_Node* node;
  97. pysqlite_Node* ptr;
  98. PyObject* data;
  99. node = (pysqlite_Node*)PyDict_GetItem(self->mapping, key);
  100. if (node) {
  101. /* an entry for this key already exists in the cache */
  102. /* increase usage counter of the node found */
  103. if (node->count < LONG_MAX) {
  104. node->count++;
  105. }
  106. /* if necessary, reorder entries in the cache by swapping positions */
  107. if (node->prev && node->count > node->prev->count) {
  108. ptr = node->prev;
  109. while (ptr->prev && node->count > ptr->prev->count) {
  110. ptr = ptr->prev;
  111. }
  112. if (node->next) {
  113. node->next->prev = node->prev;
  114. } else {
  115. self->last = node->prev;
  116. }
  117. if (node->prev) {
  118. node->prev->next = node->next;
  119. }
  120. if (ptr->prev) {
  121. ptr->prev->next = node;
  122. } else {
  123. self->first = node;
  124. }
  125. node->next = ptr;
  126. node->prev = ptr->prev;
  127. if (!node->prev) {
  128. self->first = node;
  129. }
  130. ptr->prev = node;
  131. }
  132. } else {
  133. /* There is no entry for this key in the cache, yet. We'll insert a new
  134. * entry in the cache, and make space if necessary by throwing the
  135. * least used item out of the cache. */
  136. if (PyDict_Size(self->mapping) == self->size) {
  137. if (self->last) {
  138. node = self->last;
  139. if (PyDict_DelItem(self->mapping, self->last->key) != 0) {
  140. return NULL;
  141. }
  142. if (node->prev) {
  143. node->prev->next = NULL;
  144. }
  145. self->last = node->prev;
  146. node->prev = NULL;
  147. Py_DECREF(node);
  148. }
  149. }
  150. data = PyObject_CallFunction(self->factory, "O", key);
  151. if (!data) {
  152. return NULL;
  153. }
  154. node = pysqlite_new_node(key, data);
  155. if (!node) {
  156. return NULL;
  157. }
  158. node->prev = self->last;
  159. Py_DECREF(data);
  160. if (PyDict_SetItem(self->mapping, key, (PyObject*)node) != 0) {
  161. Py_DECREF(node);
  162. return NULL;
  163. }
  164. if (self->last) {
  165. self->last->next = node;
  166. } else {
  167. self->first = node;
  168. }
  169. self->last = node;
  170. }
  171. Py_INCREF(node->data);
  172. return node->data;
  173. }
  174. PyObject* pysqlite_cache_display(pysqlite_Cache* self, PyObject* args)
  175. {
  176. pysqlite_Node* ptr;
  177. PyObject* prevkey;
  178. PyObject* nextkey;
  179. PyObject* fmt_args;
  180. PyObject* template;
  181. PyObject* display_str;
  182. ptr = self->first;
  183. while (ptr) {
  184. if (ptr->prev) {
  185. prevkey = ptr->prev->key;
  186. } else {
  187. prevkey = Py_None;
  188. }
  189. Py_INCREF(prevkey);
  190. if (ptr->next) {
  191. nextkey = ptr->next->key;
  192. } else {
  193. nextkey = Py_None;
  194. }
  195. Py_INCREF(nextkey);
  196. fmt_args = Py_BuildValue("OOO", prevkey, ptr->key, nextkey);
  197. if (!fmt_args) {
  198. return NULL;
  199. }
  200. template = PyString_FromString("%s <- %s ->%s\n");
  201. if (!template) {
  202. Py_DECREF(fmt_args);
  203. return NULL;
  204. }
  205. display_str = PyString_Format(template, fmt_args);
  206. Py_DECREF(template);
  207. Py_DECREF(fmt_args);
  208. if (!display_str) {
  209. return NULL;
  210. }
  211. PyObject_Print(display_str, stdout, Py_PRINT_RAW);
  212. Py_DECREF(display_str);
  213. Py_DECREF(prevkey);
  214. Py_DECREF(nextkey);
  215. ptr = ptr->next;
  216. }
  217. Py_INCREF(Py_None);
  218. return Py_None;
  219. }
  220. static PyMethodDef cache_methods[] = {
  221. {"get", (PyCFunction)pysqlite_cache_get, METH_O,
  222. PyDoc_STR("Gets an entry from the cache or calls the factory function to produce one.")},
  223. {"display", (PyCFunction)pysqlite_cache_display, METH_NOARGS,
  224. PyDoc_STR("For debugging only.")},
  225. {NULL, NULL}
  226. };
  227. PyTypeObject pysqlite_NodeType = {
  228. PyVarObject_HEAD_INIT(NULL, 0)
  229. MODULE_NAME "Node", /* tp_name */
  230. sizeof(pysqlite_Node), /* tp_basicsize */
  231. 0, /* tp_itemsize */
  232. (destructor)pysqlite_node_dealloc, /* tp_dealloc */
  233. 0, /* tp_print */
  234. 0, /* tp_getattr */
  235. 0, /* tp_setattr */
  236. 0, /* tp_compare */
  237. 0, /* tp_repr */
  238. 0, /* tp_as_number */
  239. 0, /* tp_as_sequence */
  240. 0, /* tp_as_mapping */
  241. 0, /* tp_hash */
  242. 0, /* tp_call */
  243. 0, /* tp_str */
  244. 0, /* tp_getattro */
  245. 0, /* tp_setattro */
  246. 0, /* tp_as_buffer */
  247. Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
  248. 0, /* tp_doc */
  249. 0, /* tp_traverse */
  250. 0, /* tp_clear */
  251. 0, /* tp_richcompare */
  252. 0, /* tp_weaklistoffset */
  253. 0, /* tp_iter */
  254. 0, /* tp_iternext */
  255. 0, /* tp_methods */
  256. 0, /* tp_members */
  257. 0, /* tp_getset */
  258. 0, /* tp_base */
  259. 0, /* tp_dict */
  260. 0, /* tp_descr_get */
  261. 0, /* tp_descr_set */
  262. 0, /* tp_dictoffset */
  263. (initproc)0, /* tp_init */
  264. 0, /* tp_alloc */
  265. 0, /* tp_new */
  266. 0 /* tp_free */
  267. };
  268. PyTypeObject pysqlite_CacheType = {
  269. PyVarObject_HEAD_INIT(NULL, 0)
  270. MODULE_NAME ".Cache", /* tp_name */
  271. sizeof(pysqlite_Cache), /* tp_basicsize */
  272. 0, /* tp_itemsize */
  273. (destructor)pysqlite_cache_dealloc, /* tp_dealloc */
  274. 0, /* tp_print */
  275. 0, /* tp_getattr */
  276. 0, /* tp_setattr */
  277. 0, /* tp_compare */
  278. 0, /* tp_repr */
  279. 0, /* tp_as_number */
  280. 0, /* tp_as_sequence */
  281. 0, /* tp_as_mapping */
  282. 0, /* tp_hash */
  283. 0, /* tp_call */
  284. 0, /* tp_str */
  285. 0, /* tp_getattro */
  286. 0, /* tp_setattro */
  287. 0, /* tp_as_buffer */
  288. Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
  289. 0, /* tp_doc */
  290. 0, /* tp_traverse */
  291. 0, /* tp_clear */
  292. 0, /* tp_richcompare */
  293. 0, /* tp_weaklistoffset */
  294. 0, /* tp_iter */
  295. 0, /* tp_iternext */
  296. cache_methods, /* tp_methods */
  297. 0, /* tp_members */
  298. 0, /* tp_getset */
  299. 0, /* tp_base */
  300. 0, /* tp_dict */
  301. 0, /* tp_descr_get */
  302. 0, /* tp_descr_set */
  303. 0, /* tp_dictoffset */
  304. (initproc)pysqlite_cache_init, /* tp_init */
  305. 0, /* tp_alloc */
  306. 0, /* tp_new */
  307. 0 /* tp_free */
  308. };
  309. extern int pysqlite_cache_setup_types(void)
  310. {
  311. int rc;
  312. pysqlite_NodeType.tp_new = PyType_GenericNew;
  313. pysqlite_CacheType.tp_new = PyType_GenericNew;
  314. rc = PyType_Ready(&pysqlite_NodeType);
  315. if (rc < 0) {
  316. return rc;
  317. }
  318. rc = PyType_Ready(&pysqlite_CacheType);
  319. return rc;
  320. }