Python-2.7.3/Modules/_sqlite/cache.c

No issues found

  1 /* cache .c - a LRU cache
  2  *
  3  * Copyright (C) 2004-2010 Gerhard Häring <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 
 24 #include "sqlitecompat.h"
 25 #include "cache.h"
 26 #include <limits.h>
 27 
 28 /* only used internally */
 29 pysqlite_Node* pysqlite_new_node(PyObject* key, PyObject* data)
 30 {
 31     pysqlite_Node* node;
 32 
 33     node = (pysqlite_Node*) (pysqlite_NodeType.tp_alloc(&pysqlite_NodeType, 0));
 34     if (!node) {
 35         return NULL;
 36     }
 37 
 38     Py_INCREF(key);
 39     node->key = key;
 40 
 41     Py_INCREF(data);
 42     node->data = data;
 43 
 44     node->prev = NULL;
 45     node->next = NULL;
 46 
 47     return node;
 48 }
 49 
 50 void pysqlite_node_dealloc(pysqlite_Node* self)
 51 {
 52     Py_DECREF(self->key);
 53     Py_DECREF(self->data);
 54 
 55     Py_TYPE(self)->tp_free((PyObject*)self);
 56 }
 57 
 58 int pysqlite_cache_init(pysqlite_Cache* self, PyObject* args, PyObject* kwargs)
 59 {
 60     PyObject* factory;
 61     int size = 10;
 62 
 63     self->factory = NULL;
 64 
 65     if (!PyArg_ParseTuple(args, "O|i", &factory, &size)) {
 66         return -1;
 67     }
 68 
 69     /* minimum cache size is 5 entries */
 70     if (size < 5) {
 71         size = 5;
 72     }
 73     self->size = size;
 74     self->first = NULL;
 75     self->last = NULL;
 76 
 77     self->mapping = PyDict_New();
 78     if (!self->mapping) {
 79         return -1;
 80     }
 81 
 82     Py_INCREF(factory);
 83     self->factory = factory;
 84 
 85     self->decref_factory = 1;
 86 
 87     return 0;
 88 }
 89 
 90 void pysqlite_cache_dealloc(pysqlite_Cache* self)
 91 {
 92     pysqlite_Node* node;
 93     pysqlite_Node* delete_node;
 94 
 95     if (!self->factory) {
 96         /* constructor failed, just get out of here */
 97         return;
 98     }
 99 
100     /* iterate over all nodes and deallocate them */
101     node = self->first;
102     while (node) {
103         delete_node = node;
104         node = node->next;
105         Py_DECREF(delete_node);
106     }
107 
108     if (self->decref_factory) {
109         Py_DECREF(self->factory);
110     }
111     Py_DECREF(self->mapping);
112 
113     Py_TYPE(self)->tp_free((PyObject*)self);
114 }
115 
116 PyObject* pysqlite_cache_get(pysqlite_Cache* self, PyObject* args)
117 {
118     PyObject* key = args;
119     pysqlite_Node* node;
120     pysqlite_Node* ptr;
121     PyObject* data;
122 
123     node = (pysqlite_Node*)PyDict_GetItem(self->mapping, key);
124     if (node) {
125         /* an entry for this key already exists in the cache */
126 
127         /* increase usage counter of the node found */
128         if (node->count < LONG_MAX) {
129             node->count++;
130         }
131 
132         /* if necessary, reorder entries in the cache by swapping positions */
133         if (node->prev && node->count > node->prev->count) {
134             ptr = node->prev;
135 
136             while (ptr->prev && node->count > ptr->prev->count) {
137                 ptr = ptr->prev;
138             }
139 
140             if (node->next) {
141                 node->next->prev = node->prev;
142             } else {
143                 self->last = node->prev;
144             }
145             if (node->prev) {
146                 node->prev->next = node->next;
147             }
148             if (ptr->prev) {
149                 ptr->prev->next = node;
150             } else {
151                 self->first = node;
152             }
153 
154             node->next = ptr;
155             node->prev = ptr->prev;
156             if (!node->prev) {
157                 self->first = node;
158             }
159             ptr->prev = node;
160         }
161     } else {
162         /* There is no entry for this key in the cache, yet. We'll insert a new
163          * entry in the cache, and make space if necessary by throwing the
164          * least used item out of the cache. */
165 
166         if (PyDict_Size(self->mapping) == self->size) {
167             if (self->last) {
168                 node = self->last;
169 
170                 if (PyDict_DelItem(self->mapping, self->last->key) != 0) {
171                     return NULL;
172                 }
173 
174                 if (node->prev) {
175                     node->prev->next = NULL;
176                 }
177                 self->last = node->prev;
178                 node->prev = NULL;
179 
180                 Py_DECREF(node);
181             }
182         }
183 
184         data = PyObject_CallFunction(self->factory, "O", key);
185 
186         if (!data) {
187             return NULL;
188         }
189 
190         node = pysqlite_new_node(key, data);
191         if (!node) {
192             return NULL;
193         }
194         node->prev = self->last;
195 
196         Py_DECREF(data);
197 
198         if (PyDict_SetItem(self->mapping, key, (PyObject*)node) != 0) {
199             Py_DECREF(node);
200             return NULL;
201         }
202 
203         if (self->last) {
204             self->last->next = node;
205         } else {
206             self->first = node;
207         }
208         self->last = node;
209     }
210 
211     Py_INCREF(node->data);
212     return node->data;
213 }
214 
215 PyObject* pysqlite_cache_display(pysqlite_Cache* self, PyObject* args)
216 {
217     pysqlite_Node* ptr;
218     PyObject* prevkey;
219     PyObject* nextkey;
220     PyObject* fmt_args;
221     PyObject* template;
222     PyObject* display_str;
223 
224     ptr = self->first;
225 
226     while (ptr) {
227         if (ptr->prev) {
228             prevkey = ptr->prev->key;
229         } else {
230             prevkey = Py_None;
231         }
232         Py_INCREF(prevkey);
233 
234         if (ptr->next) {
235             nextkey = ptr->next->key;
236         } else {
237             nextkey = Py_None;
238         }
239         Py_INCREF(nextkey);
240 
241         fmt_args = Py_BuildValue("OOO", prevkey, ptr->key, nextkey);
242         if (!fmt_args) {
243             return NULL;
244         }
245         template = PyString_FromString("%s <- %s ->%s\n");
246         if (!template) {
247             Py_DECREF(fmt_args);
248             return NULL;
249         }
250         display_str = PyString_Format(template, fmt_args);
251         Py_DECREF(template);
252         Py_DECREF(fmt_args);
253         if (!display_str) {
254             return NULL;
255         }
256         PyObject_Print(display_str, stdout, Py_PRINT_RAW);
257         Py_DECREF(display_str);
258 
259         Py_DECREF(prevkey);
260         Py_DECREF(nextkey);
261 
262         ptr = ptr->next;
263     }
264 
265     Py_INCREF(Py_None);
266     return Py_None;
267 }
268 
269 static PyMethodDef cache_methods[] = {
270     {"get", (PyCFunction)pysqlite_cache_get, METH_O,
271         PyDoc_STR("Gets an entry from the cache or calls the factory function to produce one.")},
272     {"display", (PyCFunction)pysqlite_cache_display, METH_NOARGS,
273         PyDoc_STR("For debugging only.")},
274     {NULL, NULL}
275 };
276 
277 PyTypeObject pysqlite_NodeType = {
278         PyVarObject_HEAD_INIT(NULL, 0)
279         MODULE_NAME "Node",                             /* tp_name */
280         sizeof(pysqlite_Node),                          /* tp_basicsize */
281         0,                                              /* tp_itemsize */
282         (destructor)pysqlite_node_dealloc,              /* tp_dealloc */
283         0,                                              /* tp_print */
284         0,                                              /* tp_getattr */
285         0,                                              /* tp_setattr */
286         0,                                              /* tp_compare */
287         0,                                              /* tp_repr */
288         0,                                              /* tp_as_number */
289         0,                                              /* tp_as_sequence */
290         0,                                              /* tp_as_mapping */
291         0,                                              /* tp_hash */
292         0,                                              /* tp_call */
293         0,                                              /* tp_str */
294         0,                                              /* tp_getattro */
295         0,                                              /* tp_setattro */
296         0,                                              /* tp_as_buffer */
297         Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,         /* tp_flags */
298         0,                                              /* tp_doc */
299         0,                                              /* tp_traverse */
300         0,                                              /* tp_clear */
301         0,                                              /* tp_richcompare */
302         0,                                              /* tp_weaklistoffset */
303         0,                                              /* tp_iter */
304         0,                                              /* tp_iternext */
305         0,                                              /* tp_methods */
306         0,                                              /* tp_members */
307         0,                                              /* tp_getset */
308         0,                                              /* tp_base */
309         0,                                              /* tp_dict */
310         0,                                              /* tp_descr_get */
311         0,                                              /* tp_descr_set */
312         0,                                              /* tp_dictoffset */
313         (initproc)0,                                    /* tp_init */
314         0,                                              /* tp_alloc */
315         0,                                              /* tp_new */
316         0                                               /* tp_free */
317 };
318 
319 PyTypeObject pysqlite_CacheType = {
320         PyVarObject_HEAD_INIT(NULL, 0)
321         MODULE_NAME ".Cache",                           /* tp_name */
322         sizeof(pysqlite_Cache),                         /* tp_basicsize */
323         0,                                              /* tp_itemsize */
324         (destructor)pysqlite_cache_dealloc,             /* tp_dealloc */
325         0,                                              /* tp_print */
326         0,                                              /* tp_getattr */
327         0,                                              /* tp_setattr */
328         0,                                              /* tp_compare */
329         0,                                              /* tp_repr */
330         0,                                              /* tp_as_number */
331         0,                                              /* tp_as_sequence */
332         0,                                              /* tp_as_mapping */
333         0,                                              /* tp_hash */
334         0,                                              /* tp_call */
335         0,                                              /* tp_str */
336         0,                                              /* tp_getattro */
337         0,                                              /* tp_setattro */
338         0,                                              /* tp_as_buffer */
339         Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,         /* tp_flags */
340         0,                                              /* tp_doc */
341         0,                                              /* tp_traverse */
342         0,                                              /* tp_clear */
343         0,                                              /* tp_richcompare */
344         0,                                              /* tp_weaklistoffset */
345         0,                                              /* tp_iter */
346         0,                                              /* tp_iternext */
347         cache_methods,                                  /* tp_methods */
348         0,                                              /* tp_members */
349         0,                                              /* tp_getset */
350         0,                                              /* tp_base */
351         0,                                              /* tp_dict */
352         0,                                              /* tp_descr_get */
353         0,                                              /* tp_descr_set */
354         0,                                              /* tp_dictoffset */
355         (initproc)pysqlite_cache_init,                  /* tp_init */
356         0,                                              /* tp_alloc */
357         0,                                              /* tp_new */
358         0                                               /* tp_free */
359 };
360 
361 extern int pysqlite_cache_setup_types(void)
362 {
363     int rc;
364 
365     pysqlite_NodeType.tp_new = PyType_GenericNew;
366     pysqlite_CacheType.tp_new = PyType_GenericNew;
367 
368     rc = PyType_Ready(&pysqlite_NodeType);
369     if (rc < 0) {
370         return rc;
371     }
372 
373     rc = PyType_Ready(&pysqlite_CacheType);
374     return rc;
375 }