root/src/common/db.c @ 9

Revision 1, 77.6 kB (checked in by jinshiro, 17 years ago)
Line 
1/*****************************************************************************\
2 *  Copyright (c) Athena Dev Teams - Licensed under GNU GPL
3 *  For more information, see LICENCE in the main folder
4 *
5 *  This file is separated in five sections:
6 *  (1) Private typedefs, enums, structures, defines and gblobal variables
7 *  (2) Private functions
8 *  (3) Protected functions used internally
9 *  (4) Protected functions used in the interface of the database
10 *  (5) Public functions
11 *
12 *  The databases are structured as a hashtable of RED-BLACK trees.
13 *
14 *  <B>Properties of the RED-BLACK trees being used:</B>
15 *  1. The value of any node is greater than the value of its left child and
16 *     less than the value of its right child.
17 *  2. Every node is colored either RED or BLACK.
18 *  3. Every red node that is not a leaf has only black children.
19 *  4. Every path from the root to a leaf contains the same number of black
20 *     nodes.
21 *  5. The root node is black.
22 *  An <code>n</code> node in a RED-BLACK tree has the property that its
23 *  height is <code>O(lg(n))</code>.
24 *  Another important property is that after adding a node to a RED-BLACK
25 *  tree, the tree can be readjusted in <code>O(lg(n))</code> time.
26 *  Similarly, after deleting a node from a RED-BLACK tree, the tree can be
27 *  readjusted in <code>O(lg(n))</code> time.
28 *  {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/}
29 *
30 *  <B>How to add new database types:</B>
31 *  1. Add the identifier of the new database type to the enum DBType
32 *  2. If not already there, add the data type of the key to the union DBKey
33 *  3. If the key can be considered NULL, update the function db_is_key_null
34 *  4. If the key can be duplicated, update the functions db_dup_key and
35 *     db_dup_key_free
36 *  5. Create a comparator and update the function db_default_cmp
37 *  6. Create a hasher and update the function db_default_hash
38 *  7. If the new database type requires or does not support some options,
39 *     update the function db_fix_options
40 *
41 *  TODO:
42 *  - create test cases to test the database system thoroughly
43 *  - make data an enumeration
44 *  - finish this header describing the database system
45 *  - create custom database allocator
46 *  - make the system thread friendly
47 *  - change the structure of the database to T-Trees
48 *  - create a db that organizes itself by splaying
49 *
50 *  HISTORY:
51 *    2008/02/19 - Fixed db_obj_get not handling deleted entries correctly.
52 *    2007/11/09 - Added an iterator to the database.
53 *    2006/12/21 - Added 1-node cache to the database.
54 *    2.1 (Athena build #???#) - Portability fix
55 *      - Fixed the portability of casting to union and added the functions
56 *        ensure and clear to the database.
57 *    2.0 (Athena build 4859) - Transition version
58 *      - Almost everything recoded with a strategy similar to objects,
59 *        database structure is maintained.
60 *    1.0 (up to Athena build 4706)
61 *      - Previous database system.
62 *
63 * @version 2006/12/21
64 * @author Athena Dev team
65 * @encoding US-ASCII
66 * @see #db.h
67\*****************************************************************************/
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71
72#include "db.h"
73#include "../common/mmo.h"
74#include "../common/malloc.h"
75#include "../common/showmsg.h"
76#include "../common/ers.h"
77
78/*****************************************************************************\
79 *  (1) Private typedefs, enums, structures, defines and global variables of *
80 *  the database system.                                                     *
81 *  DB_ENABLE_STATS - Define to enable database statistics.                  *
82 *  HASH_SIZE       - Define with the size of the hashtable.                 *
83 *  DBNColor        - Enumeration of colors of the nodes.                    *
84 *  DBNode          - Structure of a node in RED-BLACK trees.                *
85 *  struct db_free  - Structure that holds a deleted node to be freed.       *
86 *  DBMap_impl      - Struture of the database.                              *
87 *  stats           - Statistics about the database system.                  *
88\*****************************************************************************/
89
90/**
91 * If defined statistics about database nodes, database creating/destruction
92 * and function usage are keept and displayed when finalizing the database
93 * system.
94 * WARNING: This adds overhead to every database operation (not shure how much).
95 * @private
96 * @see #DBStats
97 * @see #stats
98 * @see #db_final(void)
99 */
100//#define DB_ENABLE_STATS
101
102/**
103 * Size of the hashtable in the database.
104 * @private
105 * @see DBMap_impl#ht
106 */
107#define HASH_SIZE (256+27)
108
109/**
110 * The color of individual nodes.
111 * @private
112 * @see struct dbn
113 */
114typedef enum node_color {
115        RED,
116        BLACK
117} node_color;
118
119/**
120 * A node in a RED-BLACK tree of the database.
121 * @param parent Parent node
122 * @param left Left child node
123 * @param right Right child node
124 * @param key Key of this database entry
125 * @param data Data of this database entry
126 * @param deleted If the node is deleted
127 * @param color Color of the node
128 * @private
129 * @see DBMap_impl#ht
130 */
131typedef struct dbn {
132        // Tree structure
133        struct dbn *parent;
134        struct dbn *left;
135        struct dbn *right;
136        // Node data
137        DBKey key;
138        void *data;
139        // Other
140        node_color color;
141        unsigned deleted : 1;
142} *DBNode;
143
144/**
145 * Structure that holds a deleted node.
146 * @param node Deleted node
147 * @param root Address to the root of the tree
148 * @private
149 * @see DBMap_impl#free_list
150 */
151struct db_free {
152        DBNode node;
153        DBNode *root;
154};
155
156/**
157 * Complete database structure.
158 * @param vtable Interface of the database
159 * @param alloc_file File where the database was allocated
160 * @param alloc_line Line in the file where the database was allocated
161 * @param free_list Array of deleted nodes to be freed
162 * @param free_count Number of deleted nodes in free_list
163 * @param free_max Current maximum capacity of free_list
164 * @param free_lock Lock for freeing the nodes
165 * @param nodes Manager of reusable tree nodes
166 * @param cmp Comparator of the database
167 * @param hash Hasher of the database
168 * @param release Releaser of the database
169 * @param ht Hashtable of RED-BLACK trees
170 * @param type Type of the database
171 * @param options Options of the database
172 * @param item_count Number of items in the database
173 * @param maxlen Maximum length of strings in DB_STRING and DB_ISTRING databases
174 * @param global_lock Global lock of the database
175 * @private
176 * @see #db_alloc(const char*,int,DBType,DBOptions,unsigned short)
177 */
178typedef struct DBMap_impl {
179        // Database interface
180        struct DBMap vtable;
181        // File and line of allocation
182        const char *alloc_file;
183        int alloc_line;
184        // Lock system
185        struct db_free *free_list;
186        unsigned int free_count;
187        unsigned int free_max;
188        unsigned int free_lock;
189        // Other
190        ERS nodes;
191        DBComparator cmp;
192        DBHasher hash;
193        DBReleaser release;
194        DBNode ht[HASH_SIZE];
195        DBNode cache;
196        DBType type;
197        DBOptions options;
198        uint32 item_count;
199        unsigned short maxlen;
200        unsigned global_lock : 1;
201} DBMap_impl;
202
203/**
204 * Complete iterator structure.
205 * @param vtable Interface of the iterator
206 * @param db Parent database
207 * @param ht_index Current index of the hashtable
208 * @param node Current node
209 * @private
210 * @see #DBIterator
211 * @see #DBMap_impl
212 * @see #DBNode
213 */
214typedef struct DBIterator_impl {
215        // Iterator interface
216        struct DBIterator vtable;
217        DBMap_impl* db;
218        int ht_index;
219        DBNode node;
220} DBIterator_impl;
221
222#if defined(DB_ENABLE_STATS)
223/**
224 * Structure with what is counted when the database estatistics are enabled.
225 * @private
226 * @see #DB_ENABLE_STATS
227 * @see #stats
228 */
229static struct db_stats {
230        // Node alloc/free
231        uint32 db_node_alloc;
232        uint32 db_node_free;
233        // Database creating/destruction counters
234        uint32 db_int_alloc;
235        uint32 db_uint_alloc;
236        uint32 db_string_alloc;
237        uint32 db_istring_alloc;
238        uint32 db_int_destroy;
239        uint32 db_uint_destroy;
240        uint32 db_string_destroy;
241        uint32 db_istring_destroy;
242        // Function usage counters
243        uint32 db_rotate_left;
244        uint32 db_rotate_right;
245        uint32 db_rebalance;
246        uint32 db_rebalance_erase;
247        uint32 db_is_key_null;
248        uint32 db_dup_key;
249        uint32 db_dup_key_free;
250        uint32 db_free_add;
251        uint32 db_free_remove;
252        uint32 db_free_lock;
253        uint32 db_free_unlock;
254        uint32 db_int_cmp;
255        uint32 db_uint_cmp;
256        uint32 db_string_cmp;
257        uint32 db_istring_cmp;
258        uint32 db_int_hash;
259        uint32 db_uint_hash;
260        uint32 db_string_hash;
261        uint32 db_istring_hash;
262        uint32 db_release_nothing;
263        uint32 db_release_key;
264        uint32 db_release_data;
265        uint32 db_release_both;
266        uint32 dbit_first;
267        uint32 dbit_last;
268        uint32 dbit_next;
269        uint32 dbit_prev;
270        uint32 dbit_exists;
271        uint32 dbit_remove;
272        uint32 dbit_destroy;
273        uint32 db_iterator;
274        uint32 db_get;
275        uint32 db_getall;
276        uint32 db_vgetall;
277        uint32 db_ensure;
278        uint32 db_vensure;
279        uint32 db_put;
280        uint32 db_remove;
281        uint32 db_foreach;
282        uint32 db_vforeach;
283        uint32 db_clear;
284        uint32 db_vclear;
285        uint32 db_destroy;
286        uint32 db_vdestroy;
287        uint32 db_size;
288        uint32 db_type;
289        uint32 db_options;
290        uint32 db_fix_options;
291        uint32 db_default_cmp;
292        uint32 db_default_hash;
293        uint32 db_default_release;
294        uint32 db_custom_release;
295        uint32 db_alloc;
296        uint32 db_i2key;
297        uint32 db_ui2key;
298        uint32 db_str2key;
299        uint32 db_init;
300        uint32 db_final;
301} stats = {
302        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
303        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
304        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
305        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
307        0, 0, 0, 0, 0, 0, 0, 0
308};
309#define DB_COUNTSTAT(token) if (stats. ## token != UINT32_MAX) ++stats. ## token
310#else /* !defined(DB_ENABLE_STATS) */
311#define DB_COUNTSTAT(token)
312#endif /* !defined(DB_ENABLE_STATS) */
313
314/*****************************************************************************\
315 *  (2) Section of private functions used by the database system.            *
316 *  db_rotate_left     - Rotate a tree node to the left.                     *
317 *  db_rotate_right    - Rotate a tree node to the right.                    *
318 *  db_rebalance       - Rebalance the tree.                                 *
319 *  db_rebalance_erase - Rebalance the tree after a BLACK node was erased.   *
320 *  db_is_key_null     - Returns not 0 if the key is considered NULL.        *
321 *  db_dup_key         - Duplicate a key for internal use.                   *
322 *  db_dup_key_free    - Free the duplicated key.                            *
323 *  db_free_add        - Add a node to the free_list of a database.          *
324 *  db_free_remove     - Remove a node from the free_list of a database.     *
325 *  db_free_lock       - Increment the free_lock of a database.              *
326 *  db_free_unlock     - Decrement the free_lock of a database.              *
327 *         If it was the last lock, frees the nodes in free_list.            *
328 *         NOTE: Keeps the database trees balanced.                          *
329\*****************************************************************************/
330
331/**
332 * Rotate a node to the left.
333 * @param node Node to be rotated
334 * @param root Pointer to the root of the tree
335 * @private
336 * @see #db_rebalance(DBNode,DBNode *)
337 * @see #db_rebalance_erase(DBNode,DBNode *)
338 */
339static void db_rotate_left(DBNode node, DBNode *root)
340{
341        DBNode y = node->right;
342
343        DB_COUNTSTAT(db_rotate_left);
344        // put the left of y at the right of node
345        node->right = y->left;
346        if (y->left)
347                y->left->parent = node;
348        y->parent = node->parent;
349        // link y and node's parent
350        if (node == *root) {
351                *root = y; // node was root
352        } else if (node == node->parent->left) {
353                node->parent->left = y; // node was at the left
354        } else {
355                node->parent->right = y; // node was at the right
356        }
357        // put node at the left of y
358        y->left = node;
359        node->parent = y;
360}
361
362/**
363 * Rotate a node to the right
364 * @param node Node to be rotated
365 * @param root Pointer to the root of the tree
366 * @private
367 * @see #db_rebalance(DBNode,DBNode *)
368 * @see #db_rebalance_erase(DBNode,DBNode *)
369 */
370static void db_rotate_right(DBNode node, DBNode *root)
371{
372        DBNode y = node->left;
373
374        DB_COUNTSTAT(db_rotate_right);
375        // put the right of y at the left of node
376        node->left = y->right;
377        if (y->right != 0)
378                y->right->parent = node;
379        y->parent = node->parent;
380        // link y and node's parent
381        if (node == *root) {
382                *root = y; // node was root
383        } else if (node == node->parent->right) {
384                node->parent->right = y; // node was at the right
385        } else {
386                node->parent->left = y; // node was at the left
387        }
388        // put node at the right of y
389        y->right = node;
390        node->parent = y;
391}
392
393/**
394 * Rebalance the RED-BLACK tree.
395 * Called when the node and it's parent are both RED.
396 * @param node Node to be rebalanced
397 * @param root Pointer to the root of the tree
398 * @private
399 * @see #db_rotate_left(DBNode,DBNode *)
400 * @see #db_rotate_right(DBNode,DBNode *)
401 * @see #db_obj_put(DBMap*,DBKey,void *)
402 */
403static void db_rebalance(DBNode node, DBNode *root)
404{
405        DBNode y;
406
407        DB_COUNTSTAT(db_rebalance);
408        // Restore the RED-BLACK properties
409        node->color = RED;
410        while (node != *root && node->parent->color == RED) {
411                if (node->parent == node->parent->parent->left) {
412                        // If node's parent is a left, y is node's right 'uncle'
413                        y = node->parent->parent->right;
414                        if (y && y->color == RED) { // case 1
415                                // change the colors and move up the tree
416                                node->parent->color = BLACK;
417                                y->color = BLACK;
418                                node->parent->parent->color = RED;
419                                node = node->parent->parent;
420                        } else {
421                                if (node == node->parent->right) { // case 2
422                                        // move up and rotate
423                                        node = node->parent;
424                                        db_rotate_left(node, root);
425                                }
426                                // case 3
427                                node->parent->color = BLACK;
428                                node->parent->parent->color = RED;
429                                db_rotate_right(node->parent->parent, root);
430                        }
431                } else {
432                        // If node's parent is a right, y is node's left 'uncle'
433                        y = node->parent->parent->left;
434                        if (y && y->color == RED) { // case 1
435                                // change the colors and move up the tree
436                                node->parent->color = BLACK;
437                                y->color = BLACK;
438                                node->parent->parent->color = RED;
439                                node = node->parent->parent;
440                        } else {
441                                if (node == node->parent->left) { // case 2
442                                        // move up and rotate
443                                        node = node->parent;
444                                        db_rotate_right(node, root);
445                                }
446                                // case 3
447                                node->parent->color = BLACK;
448                                node->parent->parent->color = RED;
449                                db_rotate_left(node->parent->parent, root);
450                        }
451                }
452        }
453        (*root)->color = BLACK; // the root can and should always be black
454}
455
456/**
457 * Erase a node from the RED-BLACK tree, keeping the tree balanced.
458 * @param node Node to be erased from the tree
459 * @param root Root of the tree
460 * @private
461 * @see #db_rotate_left(DBNode,DBNode *)
462 * @see #db_rotate_right(DBNode,DBNode *)
463 * @see #db_free_unlock(DBMap_impl*)
464 */
465static void db_rebalance_erase(DBNode node, DBNode *root)
466{
467        DBNode y = node;
468        DBNode x = NULL;
469        DBNode x_parent = NULL;
470        DBNode w;
471
472        DB_COUNTSTAT(db_rebalance_erase);
473        // Select where to change the tree
474        if (y->left == NULL) { // no left
475                x = y->right;
476        } else if (y->right == NULL) { // no right
477                x = y->left;
478        } else { // both exist, go to the leftmost node of the right sub-tree
479                y = y->right;
480                while (y->left != NULL)
481                        y = y->left;
482                x = y->right;
483        }
484
485        // Remove the node from the tree
486        if (y != node) { // both childs existed
487                // put the left of 'node' in the left of 'y'
488                node->left->parent = y;
489                y->left = node->left;
490
491                // 'y' is not the direct child of 'node'
492                if (y != node->right) {
493                        // put 'x' in the old position of 'y'
494                        x_parent = y->parent;
495                        if (x) x->parent = y->parent;
496                        y->parent->left = x;
497                        // put the right of 'node' in 'y'
498                        y->right = node->right;
499                        node->right->parent = y;
500                // 'y' is a direct child of 'node'
501                } else {
502                        x_parent = y;
503                }
504
505                // link 'y' and the parent of 'node'
506                if (*root == node) {
507                        *root = y; // 'node' was the root
508                } else if (node->parent->left == node) {
509                        node->parent->left = y; // 'node' was at the left
510                } else {
511                        node->parent->right = y; // 'node' was at the right
512                }
513                y->parent = node->parent;
514                // switch colors
515                {
516                        node_color tmp = y->color;
517                        y->color = node->color;
518                        node->color = tmp;
519                }
520                y = node;
521        } else { // one child did not exist
522                // put x in node's position
523                x_parent = y->parent;
524                if (x) x->parent = y->parent;
525                // link x and node's parent
526                if (*root == node) {
527                        *root = x; // node was the root
528                } else if (node->parent->left == node) {
529                        node->parent->left = x; // node was at the left
530                } else {
531                        node->parent->right = x;  // node was at the right
532                }
533        }
534
535        // Restore the RED-BLACK properties
536        if (y->color != RED) {
537                while (x != *root && (x == NULL || x->color == BLACK)) {
538                        if (x == x_parent->left) {
539                                w = x_parent->right;
540                                if (w->color == RED) {
541                                        w->color = BLACK;
542                                        x_parent->color = RED;
543                                        db_rotate_left(x_parent, root);
544                                        w = x_parent->right;
545                                }
546                                if ((w->left == NULL || w->left->color == BLACK) &&
547                                        (w->right == NULL || w->right->color == BLACK)) {
548                                        w->color = RED;
549                                        x = x_parent;
550                                        x_parent = x_parent->parent;
551                                } else {
552                                        if (w->right == NULL || w->right->color == BLACK) {
553                                                if (w->left) w->left->color = BLACK;
554                                                w->color = RED;
555                                                db_rotate_right(w, root);
556                                                w = x_parent->right;
557                                        }
558                                        w->color = x_parent->color;
559                                        x_parent->color = BLACK;
560                                        if (w->right) w->right->color = BLACK;
561                                        db_rotate_left(x_parent, root);
562                                        break;
563                                }
564                        } else {
565                                w = x_parent->left;
566                                if (w->color == RED) {
567                                        w->color = BLACK;
568                                        x_parent->color = RED;
569                                        db_rotate_right(x_parent, root);
570                                        w = x_parent->left;
571                                }
572                                if ((w->right == NULL || w->right->color == BLACK) &&
573                                        (w->left == NULL || w->left->color == BLACK)) {
574                                        w->color = RED;
575                                        x = x_parent;
576                                        x_parent = x_parent->parent;
577                                } else {
578                                        if (w->left == NULL || w->left->color == BLACK) {
579                                                if (w->right) w->right->color = BLACK;
580                                                w->color = RED;
581                                                db_rotate_left(w, root);
582                                                w = x_parent->left;
583                                        }
584                                        w->color = x_parent->color;
585                                        x_parent->color = BLACK;
586                                        if (w->left) w->left->color = BLACK;
587                                        db_rotate_right(x_parent, root);
588                                        break;
589                                }
590                        }
591                }
592                if (x) x->color = BLACK;
593        }
594}
595
596/**
597 * Returns not 0 if the key is considerd to be NULL.
598 * @param type Type of database
599 * @param key Key being tested
600 * @return not 0 if considered NULL, 0 otherwise
601 * @private
602 * @see #db_obj_get(DBMap*,DBKey)
603 * @see #db_obj_put(DBMap*,DBKey,void *)
604 * @see #db_obj_remove(DBMap*,DBKey)
605 */
606static int db_is_key_null(DBType type, DBKey key)
607{
608        DB_COUNTSTAT(db_is_key_null);
609        switch (type) {
610                case DB_STRING:
611                case DB_ISTRING:
612                        return (key.str == NULL);
613
614                default: // Not a pointer
615                        return 0;
616        }
617}
618
619/**
620 * Duplicate the key used in the database.
621 * @param db Database the key is being used in
622 * @param key Key to be duplicated
623 * @param Duplicated key
624 * @private
625 * @see #db_free_add(DBMap_impl*,DBNode,DBNode *)
626 * @see #db_free_remove(DBMap_impl*,DBNode)
627 * @see #db_obj_put(DBMap*,DBKey,void *)
628 * @see #db_dup_key_free(DBMap_impl*,DBKey)
629 */
630static DBKey db_dup_key(DBMap_impl* db, DBKey key)
631{
632        char *str;
633
634        DB_COUNTSTAT(db_dup_key);
635        switch (db->type) {
636                case DB_STRING:
637                case DB_ISTRING:
638                        if (db->maxlen) {
639                                CREATE(str, char, db->maxlen +1);
640                                strncpy(str, key.str, db->maxlen);
641                                str[db->maxlen] = '\0';
642                                key.str = str;
643                        } else {
644                                key.str = (char *)aStrdup(key.str);
645                        }
646                        return key;
647
648                default:
649                        return key;
650        }
651}
652
653/**
654 * Free a key duplicated by db_dup_key.
655 * @param db Database the key is being used in
656 * @param key Key to be freed
657 * @private
658 * @see #db_dup_key(DBMap_impl*,DBKey)
659 */
660static void db_dup_key_free(DBMap_impl* db, DBKey key)
661{
662        DB_COUNTSTAT(db_dup_key_free);
663        switch (db->type) {
664                case DB_STRING:
665                case DB_ISTRING:
666                        aFree((char*)key.str);
667                        return;
668
669                default:
670                        return;
671        }
672}
673
674/**
675 * Add a node to the free_list of the database.
676 * Marks the node as deleted.
677 * If the key isn't duplicated, the key is duplicated and released.
678 * @param db Target database
679 * @param root Root of the tree from the node
680 * @param node Target node
681 * @private
682 * @see #struct db_free
683 * @see DBMap_impl#free_list
684 * @see DBMap_impl#free_count
685 * @see DBMap_impl#free_max
686 * @see #db_obj_remove(DBMap*,DBKey)
687 * @see #db_free_remove(DBMap_impl*,DBNode)
688 */
689static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root)
690{
691        DBKey old_key;
692
693        DB_COUNTSTAT(db_free_add);
694        if (db->free_lock == (unsigned int)~0) {
695                ShowFatalError("db_free_add: free_lock overflow\n"
696                                "Database allocated at %s:%d\n",
697                                db->alloc_file, db->alloc_line);
698                exit(EXIT_FAILURE);
699        }
700        if (!(db->options&DB_OPT_DUP_KEY)) { // Make shure we have a key until the node is freed
701                old_key = node->key;
702                node->key = db_dup_key(db, node->key);
703                db->release(old_key, node->data, DB_RELEASE_KEY);
704        }
705        if (db->free_count == db->free_max) { // No more space, expand free_list
706                db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3
707                if (db->free_max <= db->free_count) {
708                        if (db->free_count == (unsigned int)~0) {
709                                ShowFatalError("db_free_add: free_count overflow\n"
710                                                "Database allocated at %s:%d\n",
711                                                db->alloc_file, db->alloc_line);
712                                exit(EXIT_FAILURE);
713                        }
714                        db->free_max = (unsigned int)~0;
715                }
716                RECREATE(db->free_list, struct db_free, db->free_max);
717        }
718        node->deleted = 1;
719        db->free_list[db->free_count].node = node;
720        db->free_list[db->free_count].root = root;
721        db->free_count++;
722        db->item_count--;
723}
724
725/**
726 * Remove a node from the free_list of the database.
727 * Marks the node as not deleted.
728 * NOTE: Frees the duplicated key of the node.
729 * @param db Target database
730 * @param node Node being removed from free_list
731 * @private
732 * @see #struct db_free
733 * @see DBMap_impl#free_list
734 * @see DBMap_impl#free_count
735 * @see #db_obj_put(DBMap*,DBKey,void*)
736 * @see #db_free_add(DBMap_impl*,DBNode*,DBNode)
737 */
738static void db_free_remove(DBMap_impl* db, DBNode node)
739{
740        unsigned int i;
741
742        DB_COUNTSTAT(db_free_remove);
743        for (i = 0; i < db->free_count; i++) {
744                if (db->free_list[i].node == node) {
745                        if (i < db->free_count -1) // copy the last item to where the removed one was
746                                memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free));
747                        db_dup_key_free(db, node->key);
748                        break;
749                }
750        }
751        node->deleted = 0;
752        if (i == db->free_count) {
753                ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line);
754        } else {
755                db->free_count--;
756        }
757        db->item_count++;
758}
759
760/**
761 * Increment the free_lock of the database.
762 * @param db Target database
763 * @private
764 * @see DBMap_impl#free_lock
765 * @see #db_unlock(DBMap_impl*)
766 */
767static void db_free_lock(DBMap_impl* db)
768{
769        DB_COUNTSTAT(db_free_lock);
770        if (db->free_lock == (unsigned int)~0) {
771                ShowFatalError("db_free_lock: free_lock overflow\n"
772                                "Database allocated at %s:%d\n",
773                                db->alloc_file, db->alloc_line);
774                exit(EXIT_FAILURE);
775        }
776        db->free_lock++;
777}
778
779/**
780 * Decrement the free_lock of the database.
781 * If it was the last lock, frees the nodes of the database.
782 * Keeps the tree balanced.
783 * NOTE: Frees the duplicated keys of the nodes
784 * @param db Target database
785 * @private
786 * @see DBMap_impl#free_lock
787 * @see #db_free_dbn(DBNode)
788 * @see #db_lock(DBMap_impl*)
789 */
790static void db_free_unlock(DBMap_impl* db)
791{
792        unsigned int i;
793
794        DB_COUNTSTAT(db_free_unlock);
795        if (db->free_lock == 0) {
796                ShowWarning("db_free_unlock: free_lock was already 0\n"
797                                "Database allocated at %s:%d\n",
798                                db->alloc_file, db->alloc_line);
799        } else {
800                db->free_lock--;
801        }
802        if (db->free_lock)
803                return; // Not last lock
804
805        for (i = 0; i < db->free_count ; i++) {
806                db_rebalance_erase(db->free_list[i].node, db->free_list[i].root);
807                db_dup_key_free(db, db->free_list[i].node->key);
808                DB_COUNTSTAT(db_node_free);
809                ers_free(db->nodes, db->free_list[i].node);
810        }
811        db->free_count = 0;
812}
813
814/*****************************************************************************\
815 *  (3) Section of protected functions used internally.                      *
816 *  NOTE: the protected functions used in the database interface are in the  *
817 *           next section.                                                   *
818 *  db_int_cmp         - Default comparator for DB_INT databases.            *
819 *  db_uint_cmp        - Default comparator for DB_UINT databases.           *
820 *  db_string_cmp      - Default comparator for DB_STRING databases.         *
821 *  db_istring_cmp     - Default comparator for DB_ISTRING databases.        *
822 *  db_int_hash        - Default hasher for DB_INT databases.                *
823 *  db_uint_hash       - Default hasher for DB_UINT databases.               *
824 *  db_string_hash     - Default hasher for DB_STRING databases.             *
825 *  db_istring_hash    - Default hasher for DB_ISTRING databases.            *
826 *  db_release_nothing - Releaser that releases nothing.                     *
827 *  db_release_key     - Releaser that only releases the key.                *
828 *  db_release_data    - Releaser that only releases the data.               *
829 *  db_release_both    - Releaser that releases key and data.                *
830\*****************************************************************************/
831
832/**
833 * Default comparator for DB_INT databases.
834 * Compares key1 to key2.
835 * Return 0 if equal, negative if lower and positive if higher.
836 * <code>maxlen</code> is ignored.
837 * @param key1 Key to be compared
838 * @param key2 Key being compared to
839 * @param maxlen Maximum length of the key to hash
840 * @return 0 if equal, negative if lower and positive if higher
841 * @see DBType#DB_INT
842 * @see #DBComparator
843 * @see #db_default_cmp(DBType)
844 */
845static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
846{
847        (void)maxlen;//not used
848        DB_COUNTSTAT(db_int_cmp);
849        if (key1.i < key2.i) return -1;
850        if (key1.i > key2.i) return 1;
851        return 0;
852}
853
854/**
855 * Default comparator for DB_UINT databases.
856 * Compares key1 to key2.
857 * Return 0 if equal, negative if lower and positive if higher.
858 * <code>maxlen</code> is ignored.
859 * @param key1 Key to be compared
860 * @param key2 Key being compared to
861 * @param maxlen Maximum length of the key to hash
862 * @return 0 if equal, negative if lower and positive if higher
863 * @see DBType#DB_UINT
864 * @see #DBComparator
865 * @see #db_default_cmp(DBType)
866 */
867static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
868{
869        (void)maxlen;//not used
870        DB_COUNTSTAT(db_uint_cmp);
871        if (key1.ui < key2.ui) return -1;
872        if (key1.ui > key2.ui) return 1;
873        return 0;
874}
875
876/**
877 * Default comparator for DB_STRING databases.
878 * Compares key1 to key2.
879 * Return 0 if equal, negative if lower and positive if higher.
880 * @param key1 Key to be compared
881 * @param key2 Key being compared to
882 * @param maxlen Maximum length of the key to hash
883 * @return 0 if equal, negative if lower and positive if higher
884 * @see DBType#DB_STRING
885 * @see #DBComparator
886 * @see #db_default_cmp(DBType)
887 */
888static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
889{
890        DB_COUNTSTAT(db_string_cmp);
891        if (maxlen == 0)
892                maxlen = UINT16_MAX;
893        return strncmp((const char *)key1.str, (const char *)key2.str, maxlen);
894}
895
896/**
897 * Default comparator for DB_ISTRING databases.
898 * Compares key1 to key2 case insensitively.
899 * Return 0 if equal, negative if lower and positive if higher.
900 * @param key1 Key to be compared
901 * @param key2 Key being compared to
902 * @param maxlen Maximum length of the key to hash
903 * @return 0 if equal, negative if lower and positive if higher
904 * @see DBType#DB_ISTRING
905 * @see #DBComparator
906 * @see #db_default_cmp(DBType)
907 */
908static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
909{
910        DB_COUNTSTAT(db_istring_cmp);
911        if (maxlen == 0)
912                maxlen = UINT16_MAX;
913        return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen);
914}
915
916/**
917 * Default hasher for DB_INT databases.
918 * Returns the value of the key as an unsigned int.
919 * <code>maxlen</code> is ignored.
920 * @param key Key to be hashed
921 * @param maxlen Maximum length of the key to hash
922 * @return hash of the key
923 * @see DBType#DB_INT
924 * @see #DBHasher
925 * @see #db_default_hash(DBType)
926 */
927static unsigned int db_int_hash(DBKey key, unsigned short maxlen)
928{
929        (void)maxlen;//not used
930        DB_COUNTSTAT(db_int_hash);
931        return (unsigned int)key.i;
932}
933
934/**
935 * Default hasher for DB_UINT databases.
936 * Just returns the value of the key.
937 * <code>maxlen</code> is ignored.
938 * @param key Key to be hashed
939 * @param maxlen Maximum length of the key to hash
940 * @return hash of the key
941 * @see DBType#DB_UINT
942 * @see #DBHasher
943 * @see #db_default_hash(DBType)
944 */
945static unsigned int db_uint_hash(DBKey key, unsigned short maxlen)
946{
947        (void)maxlen;//not used
948        DB_COUNTSTAT(db_uint_hash);
949        return key.ui;
950}
951
952/**
953 * Default hasher for DB_STRING databases.
954 * If maxlen if 0, the maximum number of maxlen is used instead.
955 * @param key Key to be hashed
956 * @param maxlen Maximum length of the key to hash
957 * @return hash of the key
958 * @see DBType#DB_STRING
959 * @see #DBHasher
960 * @see #db_default_hash(DBType)
961 */
962static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
963{
964        const char *k = key.str;
965        unsigned int hash = 0;
966        unsigned short i;
967
968        DB_COUNTSTAT(db_string_hash);
969        if (maxlen == 0)
970                maxlen = UINT16_MAX;
971
972        for (i = 0; *k; ++i) {
973                hash = (hash*33 + ((unsigned char)*k))^(hash>>24);
974                k++;
975                if (i == maxlen)
976                        break;
977        }
978
979        return hash;
980}
981
982/**
983 * Default hasher for DB_ISTRING databases.
984 * If maxlen if 0, the maximum number of maxlen is used instead.
985 * @param key Key to be hashed
986 * @param maxlen Maximum length of the key to hash
987 * @return hash of the key
988 * @see DBType#DB_ISTRING
989 * @see #db_default_hash(DBType)
990 */
991static unsigned int db_istring_hash(DBKey key, unsigned short maxlen)
992{
993        const char *k = key.str;
994        unsigned int hash = 0;
995        unsigned short i;
996
997        DB_COUNTSTAT(db_istring_hash);
998        if (maxlen == 0)
999                maxlen = UINT16_MAX;
1000
1001        for (i = 0; *k; i++) {
1002                hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24);
1003                k++;
1004                if (i == maxlen)
1005                        break;
1006        }
1007
1008        return hash;
1009}
1010
1011/**
1012 * Releaser that releases nothing.
1013 * @param key Key of the database entry
1014 * @param data Data of the database entry
1015 * @param which What is being requested to be released
1016 * @protected
1017 * @see #DBReleaser
1018 * @see #db_default_releaser(DBType,DBOptions)
1019 */
1020static void db_release_nothing(DBKey key, void *data, DBRelease which)
1021{
1022        (void)key;(void)data;(void)which;//not used
1023        DB_COUNTSTAT(db_release_nothing);
1024}
1025
1026/**
1027 * Releaser that only releases the key.
1028 * @param key Key of the database entry
1029 * @param data Data of the database entry
1030 * @param which What is being requested to be released
1031 * @protected
1032 * @see #DBReleaser
1033 * @see #db_default_release(DBType,DBOptions)
1034 */
1035static void db_release_key(DBKey key, void *data, DBRelease which)
1036{
1037        (void)data;//not used
1038        DB_COUNTSTAT(db_release_key);
1039        if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer
1040}
1041
1042/**
1043 * Releaser that only releases the data.
1044 * @param key Key of the database entry
1045 * @param data Data of the database entry
1046 * @param which What is being requested to be released
1047 * @protected
1048 * @see #DBKey
1049 * @see #DBRelease
1050 * @see #DBReleaser
1051 * @see #db_default_release(DBType,DBOptions)
1052 */
1053static void db_release_data(DBKey key, void *data, DBRelease which)
1054{
1055        (void)key;//not used
1056        DB_COUNTSTAT(db_release_data);
1057        if (which&DB_RELEASE_DATA) aFree(data);
1058}
1059
1060/**
1061 * Releaser that releases both key and data.
1062 * @param key Key of the database entry
1063 * @param data Data of the database entry
1064 * @param which What is being requested to be released
1065 * @protected
1066 * @see #DBKey
1067 * @see #DBRelease
1068 * @see #DBReleaser
1069 * @see #db_default_release(DBType,DBOptions)
1070 */
1071static void db_release_both(DBKey key, void *data, DBRelease which)
1072{
1073        DB_COUNTSTAT(db_release_both);
1074        if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer
1075        if (which&DB_RELEASE_DATA) aFree(data);
1076}
1077
1078/*****************************************************************************\
1079 *  (4) Section with protected functions used in the interface of the        *
1080 *  database and interface of the iterator.                                  *
1081 *  dbit_obj_first   - Fetches the first entry from the database.            *
1082 *  dbit_obj_last    - Fetches the last entry from the database.             *
1083 *  dbit_obj_next    - Fetches the next entry from the database.             *
1084 *  dbit_obj_prev    - Fetches the previous entry from the database.         *
1085 *  dbit_obj_exists  - Returns true if the current entry exists.             *
1086 *  dbit_obj_remove  - Remove the current entry from the database.           *
1087 *  dbit_obj_destroy - Destroys the iterator, unlocking the database and     *
1088 *           freeing used memory.                                            *
1089 *  db_obj_iterator - Return a new databse iterator.                         *
1090 *  db_obj_get      - Get the data identified by the key.                    *
1091 *  db_obj_vgetall  - Get the data of the matched entries.                   *
1092 *  db_obj_getall   - Get the data of the matched entries.                   *
1093 *  db_obj_vensure  - Get the data identified by the key, creating if it     *
1094 *           doesn't exist yet.                                              *
1095 *  db_obj_ensure   - Get the data identified by the key, creating if it     *
1096 *           doesn't exist yet.                                              *
1097 *  db_obj_put      - Put data identified by the key in the database.        *
1098 *  db_obj_remove   - Remove an entry from the database.                     *
1099 *  db_obj_vforeach - Apply a function to every entry in the database.       *
1100 *  db_obj_foreach  - Apply a function to every entry in the database.       *
1101 *  db_obj_vclear   - Remove all entries from the database.                  *
1102 *  db_obj_clear    - Remove all entries from the database.                  *
1103 *  db_obj_vdestroy - Destroy the database, freeing all the used memory.     *
1104 *  db_obj_destroy  - Destroy the database, freeing all the used memory.     *
1105 *  db_obj_size     - Return the size of the database.                       *
1106 *  db_obj_type     - Return the type of the database.                       *
1107 *  db_obj_options  - Return the options of the database.                    *
1108\*****************************************************************************/
1109
1110/**
1111 * Fetches the first entry in the database.
1112 * Returns the data of the entry.
1113 * Puts the key in out_key, if out_key is not NULL.
1114 * @param self Iterator
1115 * @param out_key Key of the entry
1116 * @return Data of the entry
1117 * @protected
1118 * @see DBIterator#first
1119 */
1120void* dbit_obj_first(DBIterator* self, DBKey* out_key)
1121{
1122        DBIterator_impl* it = (DBIterator_impl*)self;
1123       
1124        DB_COUNTSTAT(dbit_first);
1125        // position before the first entry
1126        it->ht_index = -1;
1127        it->node = NULL;
1128        // get next entry
1129        return self->next(self, out_key);
1130}
1131
1132/**
1133 * Fetches the last entry in the database.
1134 * Returns the data of the entry.
1135 * Puts the key in out_key, if out_key is not NULL.
1136 * @param self Iterator
1137 * @param out_key Key of the entry
1138 * @return Data of the entry
1139 * @protected
1140 * @see DBIterator#last
1141 */
1142void* dbit_obj_last(DBIterator* self, DBKey* out_key)
1143{
1144        DBIterator_impl* it = (DBIterator_impl*)self;
1145       
1146        DB_COUNTSTAT(dbit_last);
1147        // position after the last entry
1148        it->ht_index = HASH_SIZE;
1149        it->node = NULL;
1150        // get previous entry
1151        return self->prev(self, out_key);
1152}
1153
1154/**
1155 * Fetches the next entry in the database.
1156 * Returns the data of the entry.
1157 * Puts the key in out_key, if out_key is not NULL.
1158 * @param self Iterator
1159 * @param out_key Key of the entry
1160 * @return Data of the entry
1161 * @protected
1162 * @see DBIterator#next
1163 */
1164void* dbit_obj_next(DBIterator* self, DBKey* out_key)
1165{
1166        DBIterator_impl* it = (DBIterator_impl*)self;
1167        DBNode node;
1168        DBNode parent;
1169        struct dbn fake;
1170
1171        DB_COUNTSTAT(dbit_next);
1172        if( it->ht_index < 0 )
1173        {// get first node
1174                it->ht_index = 0;
1175                it->node = NULL;
1176        }
1177        node = it->node;
1178        memset(&fake, 0, sizeof(fake));
1179        for( ; it->ht_index < HASH_SIZE; ++(it->ht_index) )
1180        {
1181                // Iterate in the order: left tree, current node, right tree
1182                if( node == NULL )
1183                {// prepare initial node of this hash
1184                        node = it->db->ht[it->ht_index];
1185                        if( node == NULL )
1186                                continue;// next hash
1187                        fake.right = node;
1188                        node = &fake;
1189                }
1190
1191                while( node )
1192                {// next node
1193                        if( node->right )
1194                        {// continue in the right subtree
1195                                node = node->right;
1196                                while( node->left )
1197                                        node = node->left;// get leftmost node
1198                        }
1199                        else
1200                        {// continue to the next parent (recursive)
1201                                parent = node->parent;
1202                                while( parent )
1203                                {
1204                                        if( parent->right != node )
1205                                                break;
1206                                        node = parent;
1207                                        parent = node->parent;
1208                                }
1209                                if( parent == NULL )
1210                                {// next hash
1211                                        node = NULL;
1212                                        break;
1213                                }
1214                                node = parent;
1215                        }
1216
1217                        if( !node->deleted )
1218                        {// found next entry
1219                                it->node = node;
1220                                if( out_key )
1221                                        memcpy(out_key, &node->key, sizeof(DBKey));
1222                                return node->data;
1223                        }
1224                }
1225        }
1226        it->node = NULL;
1227        return NULL;// not found
1228}
1229
1230/**
1231 * Fetches the previous entry in the database.
1232 * Returns the data of the entry.
1233 * Puts the key in out_key, if out_key is not NULL.
1234 * @param self Iterator
1235 * @param out_key Key of the entry
1236 * @return Data of the entry
1237 * @protected
1238 * @see DBIterator#prev
1239 */
1240void* dbit_obj_prev(DBIterator* self, DBKey* out_key)
1241{
1242        DBIterator_impl* it = (DBIterator_impl*)self;
1243        DBNode node;
1244        DBNode parent;
1245        struct dbn fake;
1246
1247        DB_COUNTSTAT(dbit_prev);
1248        if( it->ht_index >= HASH_SIZE )
1249        {// get last node
1250                it->ht_index = HASH_SIZE-1;
1251                it->node = NULL;
1252        }
1253        node = it->node;
1254        memset(&fake, 0, sizeof(fake));
1255        for( ; it->ht_index >= 0; --(it->ht_index) )
1256        {
1257                // Iterate in the order: right tree, current node, left tree
1258                if( node == NULL )
1259                {// prepare initial node of this hash
1260                        node = it->db->ht[it->ht_index];
1261                        if( node == NULL )
1262                                continue;// next hash
1263                        fake.left = node;
1264                        node = &fake;
1265                }
1266
1267               
1268                while( node )
1269                {// next node
1270                        if( node->left )
1271                        {// continue in the left subtree
1272                                node = node->left;
1273                                while( node->right )
1274                                        node = node->right;// get rightmost node
1275                        }
1276                        else
1277                        {// continue to the next parent (recursive)
1278                                parent = node->parent;
1279                                while( parent )
1280                                {
1281                                        if( parent->left != node )
1282                                                break;
1283                                        node = parent;
1284                                        parent = node->parent;
1285                                }
1286                                if( parent == NULL )
1287                                {// next hash
1288                                        node = NULL;
1289                                        break;
1290                                }
1291                                node = parent;
1292                        }
1293
1294                        if( !node->deleted )
1295                        {// found previous entry
1296                                it->node = node;
1297                                if( out_key )
1298                                        memcpy(out_key, &node->key, sizeof(DBKey));
1299                                return node->data;
1300                        }
1301                }
1302        }
1303        it->node = NULL;
1304        return NULL;// not found
1305}
1306
1307/**
1308 * Returns true if the fetched entry exists.
1309 * The databases entries might have NULL data, so use this to to test if
1310 * the iterator is done.
1311 * @param self Iterator
1312 * @return true is the entry exists
1313 * @protected
1314 * @see DBIterator#exists
1315 */
1316bool dbit_obj_exists(DBIterator* self)
1317{
1318        DBIterator_impl* it = (DBIterator_impl*)self;
1319
1320        DB_COUNTSTAT(dbit_exists);
1321        return (it->node && !it->node->deleted);
1322}
1323
1324/**
1325 * Removes the current entry from the database.
1326 * NOTE: {@link DBIterator#exists} will return false until another entry
1327 *       is fethed
1328 * Returns the data of the entry.
1329 * @param self Iterator
1330 * @return The data of the entry or NULL if not found
1331 * @protected
1332 * @see DBMap#remove
1333 * @see DBIterator#remove
1334 */
1335void* dbit_obj_remove(DBIterator* self)
1336{
1337        DBIterator_impl* it = (DBIterator_impl*)self;
1338        DBNode node;
1339        void* data = NULL;
1340
1341        DB_COUNTSTAT(dbit_remove);
1342        node = it->node;
1343        if( node && !node->deleted )
1344        {
1345                DBMap_impl* db = it->db;
1346                if( db->cache == node )
1347                        db->cache = NULL;
1348                data = node->data;
1349                db->release(node->key, node->data, DB_RELEASE_DATA);
1350                db_free_add(db, node, &db->ht[it->ht_index]);
1351        }
1352        return data;
1353}
1354
1355/**
1356 * Destroys this iterator and unlocks the database.
1357 * @param self Iterator
1358 * @protected
1359 */
1360void dbit_obj_destroy(DBIterator* self)
1361{
1362        DBIterator_impl* it = (DBIterator_impl*)self;
1363
1364        DB_COUNTSTAT(dbit_destroy);
1365        // unlock the database
1366        db_free_unlock(it->db);
1367        // free iterator
1368        aFree(self);
1369}
1370
1371/**
1372 * Returns a new iterator for this database.
1373 * The iterator keeps the database locked until it is destroyed.
1374 * The database will keep functioning normally but will only free internal
1375 * memory when unlocked, so destroy the iterator as soon as possible.
1376 * @param self Database
1377 * @return New iterator
1378 * @protected
1379 */
1380static DBIterator* db_obj_iterator(DBMap* self)
1381{
1382        DBMap_impl* db = (DBMap_impl*)self;
1383        DBIterator_impl* it;
1384
1385        DB_COUNTSTAT(db_iterator);
1386        CREATE(it, struct DBIterator_impl, 1);
1387        /* Interface of the iterator **/
1388        it->vtable.first   = dbit_obj_first;
1389        it->vtable.last    = dbit_obj_last;
1390        it->vtable.next    = dbit_obj_next;
1391        it->vtable.prev    = dbit_obj_prev;
1392        it->vtable.exists  = dbit_obj_exists;
1393        it->vtable.remove  = dbit_obj_remove;
1394        it->vtable.destroy = dbit_obj_destroy;
1395        /* Initial state (before the first entry) */
1396        it->db = db;
1397        it->ht_index = -1;
1398        it->node = NULL;
1399        /* Lock the database */
1400        db_free_lock(db);
1401        return &it->vtable;
1402}
1403
1404/**
1405 * Get the data of the entry identifid by the key.
1406 * @param self Interface of the database
1407 * @param key Key that identifies the entry
1408 * @return Data of the entry or NULL if not found
1409 * @protected
1410 * @see DBMap#get
1411 */
1412static void* db_obj_get(DBMap* self, DBKey key)
1413{
1414        DBMap_impl* db = (DBMap_impl*)self;
1415        DBNode node;
1416        int c;
1417        void *data = NULL;
1418
1419        DB_COUNTSTAT(db_get);
1420        if (db == NULL) return NULL; // nullpo candidate
1421        if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) {
1422                ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1423                return NULL; // nullpo candidate
1424        }
1425
1426        if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) {
1427#if defined(DEBUG)
1428                if (db->cache->deleted) {
1429                        ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n");
1430                        return NULL;
1431                }
1432#endif
1433                return db->cache->data; // cache hit
1434        }
1435
1436        db_free_lock(db);
1437        node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE];
1438        while (node) {
1439                c = db->cmp(key, node->key, db->maxlen);
1440                if (c == 0) {
1441                        if (!(node->deleted)) {
1442                                data = node->data;
1443                                db->cache = node;
1444                        }
1445                        break;
1446                }
1447                if (c < 0)
1448                        node = node->left;
1449                else
1450                        node = node->right;
1451        }
1452        db_free_unlock(db);
1453        return data;
1454}
1455
1456/**
1457 * Get the data of the entries matched by <code>match</code>.
1458 * It puts a maximum of <code>max</code> entries into <code>buf</code>.
1459 * If <code>buf</code> is NULL, it only counts the matches.
1460 * Returns the number of entries that matched.
1461 * NOTE: if the value returned is greater than <code>max</code>, only the
1462 * first <code>max</code> entries found are put into the buffer.
1463 * @param self Interface of the database
1464 * @param buf Buffer to put the data of the matched entries
1465 * @param max Maximum number of data entries to be put into buf
1466 * @param match Function that matches the database entries
1467 * @param ... Extra arguments for match
1468 * @return The number of entries that matched
1469 * @protected
1470 * @see DBMap#vgetall
1471 */
1472static unsigned int db_obj_vgetall(DBMap* self, void **buf, unsigned int max, DBMatcher match, va_list args)
1473{
1474        DBMap_impl* db = (DBMap_impl*)self;
1475        unsigned int i;
1476        DBNode node;
1477        DBNode parent;
1478        unsigned int ret = 0;
1479
1480        DB_COUNTSTAT(db_vgetall);
1481        if (db == NULL) return 0; // nullpo candidate
1482        if (match == NULL) return 0; // nullpo candidate
1483
1484        db_free_lock(db);
1485        for (i = 0; i < HASH_SIZE; i++) {
1486                // Match in the order: current node, left tree, right tree
1487                node = db->ht[i];
1488                while (node) {
1489                        parent = node->parent;
1490                        if (!(node->deleted))
1491                        {
1492                                va_list argscopy;
1493                                va_copy(argscopy, args);
1494                                if (match(node->key, node->data, argscopy) == 0) {
1495                                        if (buf && ret < max)
1496                                                buf[ret] = node->data;
1497                                        ret++;
1498                                }
1499                                va_end(argscopy);
1500                        }
1501                        if (node->left) {
1502                                node = node->left;
1503                                continue;
1504                        }
1505                        if (node->right) {
1506                                node = node->right;
1507                                continue;
1508                        }
1509                        while (node) {
1510                                parent = node->parent;
1511                                if (parent && parent->right && parent->left == node) {
1512                                        node = parent->right;
1513                                        break;
1514                                }
1515                                node = parent;
1516                        }
1517                }
1518        }
1519        db_free_unlock(db);
1520        return ret;
1521}
1522
1523/**
1524 * Just calls {@link DBMap#vgetall}.
1525 * Get the data of the entries matched by <code>match</code>.
1526 * It puts a maximum of <code>max</code> entries into <code>buf</code>.
1527 * If <code>buf</code> is NULL, it only counts the matches.
1528 * Returns the number of entries that matched.
1529 * NOTE: if the value returned is greater than <code>max</code>, only the
1530 * first <code>max</code> entries found are put into the buffer.
1531 * @param self Interface of the database
1532 * @param buf Buffer to put the data of the matched entries
1533 * @param max Maximum number of data entries to be put into buf
1534 * @param match Function that matches the database entries
1535 * @param ... Extra arguments for match
1536 * @return The number of entries that matched
1537 * @protected
1538 * @see DBMap#vgetall
1539 * @see DBMap#getall
1540 */
1541static unsigned int db_obj_getall(DBMap* self, void **buf, unsigned int max, DBMatcher match, ...)
1542{
1543        va_list args;
1544        unsigned int ret;
1545
1546        DB_COUNTSTAT(db_getall);
1547        if (self == NULL) return 0; // nullpo candidate
1548
1549        va_start(args, match);
1550        ret = self->vgetall(self, buf, max, match, args);
1551        va_end(args);
1552        return ret;
1553}
1554
1555/**
1556 * Get the data of the entry identified by the key.
1557 * If the entry does not exist, an entry is added with the data returned by
1558 * <code>create</code>.
1559 * @param self Interface of the database
1560 * @param key Key that identifies the entry
1561 * @param create Function used to create the data if the entry doesn't exist
1562 * @param args Extra arguments for create
1563 * @return Data of the entry
1564 * @protected
1565 * @see DBMap#vensure
1566 */
1567static void *db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_list args)
1568{
1569        DBMap_impl* db = (DBMap_impl*)self;
1570        DBNode node;
1571        DBNode parent = NULL;
1572        unsigned int hash;
1573        int c = 0;
1574        void *data = NULL;
1575
1576        DB_COUNTSTAT(db_vensure);
1577        if (db == NULL) return NULL; // nullpo candidate
1578        if (create == NULL) {
1579                ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1580                return NULL; // nullpo candidate
1581        }
1582        if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) {
1583                ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1584                return NULL; // nullpo candidate
1585        }
1586
1587        if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0)
1588                return db->cache->data; // cache hit
1589
1590        db_free_lock(db);
1591        hash = db->hash(key, db->maxlen)%HASH_SIZE;
1592        node = db->ht[hash];
1593        while (node) {
1594                c = db->cmp(key, node->key, db->maxlen);
1595                if (c == 0) {
1596                        break;
1597                }
1598                parent = node;
1599                if (c < 0)
1600                        node = node->left;
1601                else
1602                        node = node->right;
1603        }
1604        // Create node if necessary
1605        if (node == NULL) {
1606                va_list argscopy;
1607                if (db->item_count == UINT32_MAX) {
1608                        ShowError("db_vensure: item_count overflow, aborting item insertion.\n"
1609                                        "Database allocated at %s:%d",
1610                                        db->alloc_file, db->alloc_line);
1611                                return NULL;
1612                }
1613                DB_COUNTSTAT(db_node_alloc);
1614                node = ers_alloc(db->nodes, struct dbn);
1615                node->left = NULL;
1616                node->right = NULL;
1617                node->deleted = 0;
1618                db->item_count++;
1619                if (c == 0) { // hash entry is empty
1620                        node->color = BLACK;
1621                        node->parent = NULL;
1622                        db->ht[hash] = node;
1623                } else {
1624                        node->color = RED;
1625                        if (c < 0) { // put at the left
1626                                parent->left = node;
1627                                node->parent = parent;
1628                        } else { // put at the right
1629                                parent->right = node;
1630                                node->parent = parent;
1631                        }
1632                        if (parent->color == RED) // two consecutive RED nodes, must rebalance
1633                                db_rebalance(node, &db->ht[hash]);
1634                }
1635                // put key and data in the node
1636                if (db->options&DB_OPT_DUP_KEY) {
1637                        node->key = db_dup_key(db, key);
1638                        if (db->options&DB_OPT_RELEASE_KEY)
1639                                db->release(key, data, DB_RELEASE_KEY);
1640                } else {
1641                        node->key = key;
1642                }
1643                va_copy(argscopy, args);
1644                node->data = create(key, argscopy);
1645                va_end(argscopy);
1646        }
1647        data = node->data;
1648        db->cache = node;
1649        db_free_unlock(db);
1650        return data;
1651}
1652
1653/**
1654 * Just calls {@link DBMap#vensure}.
1655 * Get the data of the entry identified by the key.
1656 * If the entry does not exist, an entry is added with the data returned by
1657 * <code>create</code>.
1658 * @param self Interface of the database
1659 * @param key Key that identifies the entry
1660 * @param create Function used to create the data if the entry doesn't exist
1661 * @param ... Extra arguments for create
1662 * @return Data of the entry
1663 * @protected
1664 * @see DBMap#vensure
1665 * @see DBMap#ensure
1666 */
1667static void *db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...)
1668{
1669        va_list args;
1670        void *ret;
1671
1672        DB_COUNTSTAT(db_ensure);
1673        if (self == NULL) return 0; // nullpo candidate
1674
1675        va_start(args, create);
1676        ret = self->vensure(self, key, create, args);
1677        va_end(args);
1678        return ret;
1679}
1680
1681/**
1682 * Put the data identified by the key in the database.
1683 * Returns the previous data if the entry exists or NULL.
1684 * NOTE: Uses the new key, the old one is released.
1685 * @param self Interface of the database
1686 * @param key Key that identifies the data
1687 * @param data Data to be put in the database
1688 * @return The previous data if the entry exists or NULL
1689 * @protected
1690 * @see #db_malloc_dbn(void)
1691 * @see DBMap#put
1692 */
1693static void *db_obj_put(DBMap* self, DBKey key, void *data)
1694{
1695        DBMap_impl* db = (DBMap_impl*)self;
1696        DBNode node;
1697        DBNode parent = NULL;
1698        int c = 0;
1699        unsigned int hash;
1700        void *old_data = NULL;
1701
1702        DB_COUNTSTAT(db_put);
1703        if (db == NULL) return NULL; // nullpo candidate
1704        if (db->global_lock) {
1705                ShowError("db_put: Database is being destroyed, aborting entry insertion.\n"
1706                                "Database allocated at %s:%d\n",
1707                                db->alloc_file, db->alloc_line);
1708                return NULL; // nullpo candidate
1709        }
1710        if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) {
1711                ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1712                return NULL; // nullpo candidate
1713        }
1714        if (!(data || db->options&DB_OPT_ALLOW_NULL_DATA)) {
1715                ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1716                return NULL; // nullpo candidate
1717        }
1718
1719        if (db->item_count == UINT32_MAX) {
1720                ShowError("db_put: item_count overflow, aborting item insertion.\n"
1721                                "Database allocated at %s:%d",
1722                                db->alloc_file, db->alloc_line);
1723                return NULL;
1724        }
1725        // search for an equal node
1726        db_free_lock(db);
1727        hash = db->hash(key, db->maxlen)%HASH_SIZE;
1728        for (node = db->ht[hash]; node; ) {
1729                c = db->cmp(key, node->key, db->maxlen);
1730                if (c == 0) { // equal entry, replace
1731                        if (node->deleted) {
1732                                db_free_remove(db, node);
1733                        } else {
1734                                db->release(node->key, node->data, DB_RELEASE_BOTH);
1735                        }
1736                        old_data = node->data;
1737                        break;
1738                }
1739                parent = node;
1740                if (c < 0) {
1741                        node = node->left;
1742                } else {
1743                        node = node->right;
1744                }
1745        }
1746        // allocate a new node if necessary
1747        if (node == NULL) {
1748                DB_COUNTSTAT(db_node_alloc);
1749                node = ers_alloc(db->nodes, struct dbn);
1750                node->left = NULL;
1751                node->right = NULL;
1752                node->deleted = 0;
1753                db->item_count++;
1754                if (c == 0) { // hash entry is empty
1755                        node->color = BLACK;
1756                        node->parent = NULL;
1757                        db->ht[hash] = node;
1758                } else {
1759                        node->color = RED;
1760                        if (c < 0) { // put at the left
1761                                parent->left = node;
1762                                node->parent = parent;
1763                        } else { // put at the right
1764                                parent->right = node;
1765                                node->parent = parent;
1766                        }
1767                        if (parent->color == RED) // two consecutive RED nodes, must rebalance
1768                                db_rebalance(node, &db->ht[hash]);
1769                }
1770        }
1771        // put key and data in the node
1772        if (db->options&DB_OPT_DUP_KEY) {
1773                node->key = db_dup_key(db, key);
1774                if (db->options&DB_OPT_RELEASE_KEY)
1775                        db->release(key, data, DB_RELEASE_KEY);
1776        } else {
1777                node->key = key;
1778        }
1779        node->data = data;
1780        db->cache = node;
1781        db_free_unlock(db);
1782        return old_data;
1783}
1784
1785/**
1786 * Remove an entry from the database.
1787 * Returns the data of the entry.
1788 * NOTE: The key (of the database) is released in {@link #db_free_add(DBMap_impl*,DBNode,DBNode *)}.
1789 * @param self Interface of the database
1790 * @param key Key that identifies the entry
1791 * @return The data of the entry or NULL if not found
1792 * @protected
1793 * @see #db_free_add(DBMap_impl*,DBNode,DBNode *)
1794 * @see DBMap#remove
1795 */
1796static void *db_obj_remove(DBMap* self, DBKey key)
1797{
1798        DBMap_impl* db = (DBMap_impl*)self;
1799        void *data = NULL;
1800        DBNode node;
1801        unsigned int hash;
1802        int c = 0;
1803
1804        DB_COUNTSTAT(db_remove);
1805        if (db == NULL) return NULL; // nullpo candidate
1806        if (db->global_lock) {
1807                ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n"
1808                                "Database allocated at %s:%d\n",
1809                                db->alloc_file, db->alloc_line);
1810                return NULL; // nullpo candidate
1811        }
1812        if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key))      {
1813                ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1814                return NULL; // nullpo candidate
1815        }
1816
1817        db_free_lock(db);
1818        hash = db->hash(key, db->maxlen)%HASH_SIZE;
1819        for(node = db->ht[hash]; node; ){
1820                c = db->cmp(key, node->key, db->maxlen);
1821                if (c == 0) {
1822                        if (!(node->deleted)) {
1823                                if (db->cache == node)
1824                                        db->cache = NULL;
1825                                data = node->data;
1826                                db->release(node->key, node->data, DB_RELEASE_DATA);
1827                                db_free_add(db, node, &db->ht[hash]);
1828                        }
1829                        break;
1830                }
1831                if (c < 0)
1832                        node = node->left;
1833                else
1834                        node = node->right;
1835        }
1836        db_free_unlock(db);
1837        return data;
1838}
1839
1840/**
1841 * Apply <code>func</code> to every entry in the database.
1842 * Returns the sum of values returned by func.
1843 * @param self Interface of the database
1844 * @param func Function to be applyed
1845 * @param args Extra arguments for func
1846 * @return Sum of the values returned by func
1847 * @protected
1848 * @see DBMap#vforeach
1849 */
1850static int db_obj_vforeach(DBMap* self, DBApply func, va_list args)
1851{
1852        DBMap_impl* db = (DBMap_impl*)self;
1853        unsigned int i;
1854        int sum = 0;
1855        DBNode node;
1856        DBNode parent;
1857
1858        DB_COUNTSTAT(db_vforeach);
1859        if (db == NULL) return 0; // nullpo candidate
1860        if (func == NULL) {
1861                ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line);
1862                return 0; // nullpo candidate
1863        }
1864
1865        db_free_lock(db);
1866        for (i = 0; i < HASH_SIZE; i++) {
1867                // Apply func in the order: current node, left node, right node
1868                node = db->ht[i];
1869                while (node) {
1870                        parent = node->parent;
1871                        if (!(node->deleted))
1872                        {
1873                                va_list argscopy;
1874                                va_copy(argscopy, args);
1875                                sum += func(node->key, node->data, argscopy);
1876                                va_end(argscopy);
1877                        }
1878                        if (node->left) {
1879                                node = node->left;
1880                                continue;
1881                        }
1882                        if (node->right) {
1883                                node = node->right;
1884                                continue;
1885                        }
1886                        while (node) {
1887                                parent = node->parent;
1888                                if (parent && parent->right && parent->left == node) {
1889                                        node = parent->right;
1890                                        break;
1891                                }
1892                                node = parent;
1893                        }
1894                }
1895        }
1896        db_free_unlock(db);
1897        return sum;
1898}
1899
1900/**
1901 * Just calls {@link DBMap#vforeach}.
1902 * Apply <code>func</code> to every entry in the database.
1903 * Returns the sum of values returned by func.
1904 * @param self Interface of the database
1905 * @param func Function to be applyed
1906 * @param ... Extra arguments for func
1907 * @return Sum of the values returned by func
1908 * @protected
1909 * @see DBMap#vforeach
1910 * @see DBMap#foreach
1911 */
1912static int db_obj_foreach(DBMap* self, DBApply func, ...)
1913{
1914        va_list args;
1915        int ret;
1916
1917        DB_COUNTSTAT(db_foreach);
1918        if (self == NULL) return 0; // nullpo candidate
1919
1920        va_start(args, func);
1921        ret = self->vforeach(self, func, args);
1922        va_end(args);
1923        return ret;
1924}
1925
1926/**
1927 * Removes all entries from the database.
1928 * Before deleting an entry, func is applyed to it.
1929 * Releases the key and the data.
1930 * Returns the sum of values returned by func, if it exists.
1931 * @param self Interface of the database
1932 * @param func Function to be applyed to every entry before deleting
1933 * @param args Extra arguments for func
1934 * @return Sum of values returned by func
1935 * @protected
1936 * @see DBMap#vclear
1937 */
1938static int db_obj_vclear(DBMap* self, DBApply func, va_list args)
1939{
1940        DBMap_impl* db = (DBMap_impl*)self;
1941        int sum = 0;
1942        unsigned int i;
1943        DBNode node;
1944        DBNode parent;
1945
1946        DB_COUNTSTAT(db_vclear);
1947        if (db == NULL) return 0; // nullpo candidate
1948
1949        db_free_lock(db);
1950        db->cache = NULL;
1951        for (i = 0; i < HASH_SIZE; i++) {
1952                // Apply the func and delete in the order: left tree, right tree, current node
1953                node = db->ht[i];
1954                db->ht[i] = NULL;
1955                while (node) {
1956                        parent = node->parent;
1957                        if (node->left) {
1958                                node = node->left;
1959                                continue;
1960                        }
1961                        if (node->right) {
1962                                node = node->right;
1963                                continue;
1964                        }
1965                        if (node->deleted) {
1966                                db_dup_key_free(db, node->key);
1967                        } else {
1968                                if (func)
1969                                {
1970                                        va_list argscopy;
1971                                        va_copy(argscopy, args);
1972                                        sum += func(node->key, node->data, argscopy);
1973                                        va_end(argscopy);
1974                                }
1975                                db->release(node->key, node->data, DB_RELEASE_BOTH);
1976                                node->deleted = 1;
1977                        }
1978                        DB_COUNTSTAT(db_node_free);
1979                        ers_free(db->nodes, node);
1980                        if (parent) {
1981                                if (parent->left == node)
1982                                        parent->left = NULL;
1983                                else
1984                                        parent->right = NULL;
1985                        }
1986                        node = parent;
1987                }
1988                db->ht[i] = NULL;
1989        }
1990        db->free_count = 0;
1991        db->item_count = 0;
1992        db_free_unlock(db);
1993        return sum;
1994}
1995
1996/**
1997 * Just calls {@link DBMap#vclear}.
1998 * Removes all entries from the database.
1999 * Before deleting an entry, func is applyed to it.
2000 * Releases the key and the data.
2001 * Returns the sum of values returned by func, if it exists.
2002 * NOTE: This locks the database globally. Any attempt to insert or remove
2003 * a database entry will give an error and be aborted (except for clearing).
2004 * @param self Interface of the database
2005 * @param func Function to be applyed to every entry before deleting
2006 * @param ... Extra arguments for func
2007 * @return Sum of values returned by func
2008 * @protected
2009 * @see DBMap#vclear
2010 * @see DBMap#clear
2011 */
2012static int db_obj_clear(DBMap* self, DBApply func, ...)
2013{
2014        va_list args;
2015        int ret;
2016
2017        DB_COUNTSTAT(db_clear);
2018        if (self == NULL) return 0; // nullpo candidate
2019
2020        va_start(args, func);
2021        ret = self->vclear(self, func, args);
2022        va_end(args);
2023        return ret;
2024}
2025
2026/**
2027 * Finalize the database, feeing all the memory it uses.
2028 * Before deleting an entry, func is applyed to it.
2029 * Returns the sum of values returned by func, if it exists.
2030 * NOTE: This locks the database globally. Any attempt to insert or remove
2031 * a database entry will give an error and be aborted (except for clearing).
2032 * @param self Interface of the database
2033 * @param func Function to be applyed to every entry before deleting
2034 * @param args Extra arguments for func
2035 * @return Sum of values returned by func
2036 * @protected
2037 * @see DBMap#vdestroy
2038 */
2039static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args)
2040{
2041        DBMap_impl* db = (DBMap_impl*)self;
2042        int sum;
2043
2044        DB_COUNTSTAT(db_vdestroy);
2045        if (db == NULL) return 0; // nullpo candidate
2046        if (db->global_lock) {
2047                ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n"
2048                                "Database allocated at %s:%d\n",
2049                                db->alloc_file, db->alloc_line);
2050                return 0;
2051        }
2052        if (db->free_lock)
2053                ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n"
2054                                "Database allocated at %s:%d\n",
2055                                db->free_lock, db->alloc_file, db->alloc_line);
2056
2057#ifdef DB_ENABLE_STATS
2058        switch (db->type) {
2059                case DB_INT: DB_COUNTSTAT(db_int_destroy); break;
2060                case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break;
2061                case DB_STRING: DB_COUNTSTAT(db_string_destroy); break;
2062                case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break;
2063        }
2064#endif /* DB_ENABLE_STATS */
2065        db_free_lock(db);
2066        db->global_lock = 1;
2067        sum = self->vclear(self, func, args);
2068        aFree(db->free_list);
2069        db->free_list = NULL;
2070        db->free_max = 0;
2071        ers_destroy(db->nodes);
2072        db_free_unlock(db);
2073        aFree(db);
2074        return sum;
2075}
2076
2077/**
2078 * Just calls {@link DBMap#db_vdestroy}.
2079 * Finalize the database, feeing all the memory it uses.
2080 * Before deleting an entry, func is applyed to it.
2081 * Releases the key and the data.
2082 * Returns the sum of values returned by func, if it exists.
2083 * NOTE: This locks the database globally. Any attempt to insert or remove
2084 * a database entry will give an error and be aborted.
2085 * @param self Database
2086 * @param func Function to be applyed to every entry before deleting
2087 * @param ... Extra arguments for func
2088 * @return Sum of values returned by func
2089 * @protected
2090 * @see DBMap#vdestroy
2091 * @see DBMap#destroy
2092 */
2093static int db_obj_destroy(DBMap* self, DBApply func, ...)
2094{
2095        va_list args;
2096        int ret;
2097
2098        DB_COUNTSTAT(db_destroy);
2099        if (self == NULL) return 0; // nullpo candidate
2100
2101        va_start(args, func);
2102        ret = self->vdestroy(self, func, args);
2103        va_end(args);
2104        return ret;
2105}
2106
2107/**
2108 * Return the size of the database (number of items in the database).
2109 * @param self Interface of the database
2110 * @return Size of the database
2111 * @protected
2112 * @see DBMap_impl#item_count
2113 * @see DBMap#size
2114 */
2115static unsigned int db_obj_size(DBMap* self)
2116{
2117        DBMap_impl* db = (DBMap_impl*)self;
2118        unsigned int item_count;
2119
2120        DB_COUNTSTAT(db_size);
2121        if (db == NULL) return 0; // nullpo candidate
2122
2123        db_free_lock(db);
2124        item_count = db->item_count;
2125        db_free_unlock(db);
2126
2127        return item_count;
2128}
2129
2130/**
2131 * Return the type of database.
2132 * @param self Interface of the database
2133 * @return Type of the database
2134 * @protected
2135 * @see DBMap_impl#type
2136 * @see DBMap#type
2137 */
2138static DBType db_obj_type(DBMap* self)
2139{
2140        DBMap_impl* db = (DBMap_impl*)self;
2141        DBType type;
2142
2143        DB_COUNTSTAT(db_type);
2144        if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return?
2145
2146        db_free_lock(db);
2147        type = db->type;
2148        db_free_unlock(db);
2149
2150        return type;
2151}
2152
2153/**
2154 * Return the options of the database.
2155 * @param self Interface of the database
2156 * @return Options of the database
2157 * @protected
2158 * @see DBMap_impl#options
2159 * @see DBMap#options
2160 */
2161static DBOptions db_obj_options(DBMap* self)
2162{
2163        DBMap_impl* db = (DBMap_impl*)self;
2164        DBOptions options;
2165
2166        DB_COUNTSTAT(db_options);
2167        if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return?
2168
2169        db_free_lock(db);
2170        options = db->options;
2171        db_free_unlock(db);
2172
2173        return options;
2174}
2175
2176/*****************************************************************************\
2177 *  (5) Section with public functions.
2178 *  db_fix_options     - Apply database type restrictions to the options.
2179 *  db_default_cmp     - Get the default comparator for a type of database.
2180 *  db_default_hash    - Get the default hasher for a type of database.
2181 *  db_default_release - Get the default releaser for a type of database with the specified options.
2182 *  db_custom_release  - Get a releaser that behaves a certains way.
2183 *  db_alloc           - Allocate a new database.
2184 *  db_i2key           - Manual cast from 'int' to 'DBKey'.
2185 *  db_ui2key          - Manual cast from 'unsigned int' to 'DBKey'.
2186 *  db_str2key         - Manual cast from 'unsigned char *' to 'DBKey'.
2187 *  db_init            - Initializes the database system.
2188 *  db_final           - Finalizes the database system.
2189\*****************************************************************************/
2190
2191/**
2192 * Returns the fixed options according to the database type.
2193 * Sets required options and unsets unsupported options.
2194 * For numeric databases DB_OPT_DUP_KEY and DB_OPT_RELEASE_KEY are unset.
2195 * @param type Type of the database
2196 * @param options Original options of the database
2197 * @return Fixed options of the database
2198 * @private
2199 * @see #db_default_release(DBType,DBOptions)
2200 * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short)
2201 */
2202DBOptions db_fix_options(DBType type, DBOptions options)
2203{
2204        DB_COUNTSTAT(db_fix_options);
2205        switch (type) {
2206                case DB_INT:
2207                case DB_UINT: // Numeric database, do nothing with the keys
2208                        return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY));
2209
2210                default:
2211                        ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options);
2212                case DB_STRING:
2213                case DB_ISTRING: // String databases, no fix required
2214                        return options;
2215        }
2216}
2217
2218/**
2219 * Returns the default comparator for the specified type of database.
2220 * @param type Type of database
2221 * @return Comparator for the type of database or NULL if unknown database
2222 * @public
2223 * @see #db_int_cmp(DBKey,DBKey,unsigned short)
2224 * @see #db_uint_cmp(DBKey,DBKey,unsigned short)
2225 * @see #db_string_cmp(DBKey,DBKey,unsigned short)
2226 * @see #db_istring_cmp(DBKey,DBKey,unsigned short)
2227 */
2228DBComparator db_default_cmp(DBType type)
2229{
2230        DB_COUNTSTAT(db_default_cmp);
2231        switch (type) {
2232                case DB_INT:     return db_int_cmp;
2233                case DB_UINT:    return db_uint_cmp;
2234                case DB_STRING:  return db_string_cmp;
2235                case DB_ISTRING: return db_istring_cmp;
2236                default:
2237                        ShowError("db_default_cmp: Unknown database type %u\n", type);
2238                        return NULL;
2239        }
2240}
2241
2242/**
2243 * Returns the default hasher for the specified type of database.
2244 * @param type Type of database
2245 * @return Hasher of the type of database or NULL if unknown database
2246 * @public
2247 * @see #db_int_hash(DBKey,unsigned short)
2248 * @see #db_uint_hash(DBKey,unsigned short)
2249 * @see #db_string_hash(DBKey,unsigned short)
2250 * @see #db_istring_hash(DBKey,unsigned short)
2251 */
2252DBHasher db_default_hash(DBType type)
2253{
2254        DB_COUNTSTAT(db_default_hash);
2255        switch (type) {
2256                case DB_INT:     return db_int_hash;
2257                case DB_UINT:    return db_uint_hash;
2258                case DB_STRING:  return db_string_hash;
2259                case DB_ISTRING: return db_istring_hash;
2260                default:
2261                        ShowError("db_default_hash: Unknown database type %u\n", type);
2262                        return NULL;
2263        }
2264}
2265
2266/**
2267 * Returns the default releaser for the specified type of database with the
2268 * specified options.
2269 * NOTE: the options are fixed with {@link #db_fix_options(DBType,DBOptions)}
2270 * before choosing the releaser.
2271 * @param type Type of database
2272 * @param options Options of the database
2273 * @return Default releaser for the type of database with the specified options
2274 * @public
2275 * @see #db_release_nothing(DBKey,void *,DBRelease)
2276 * @see #db_release_key(DBKey,void *,DBRelease)
2277 * @see #db_release_data(DBKey,void *,DBRelease)
2278 * @see #db_release_both(DBKey,void *,DBRelease)
2279 * @see #db_custom_release(DBRelease)
2280 */
2281DBReleaser db_default_release(DBType type, DBOptions options)
2282{
2283        DB_COUNTSTAT(db_default_release);
2284        options = db_fix_options(type, options);
2285        if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key?
2286                if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY))
2287                        return db_release_both; // Release both key and data
2288                return db_release_data; // Only release data
2289        }
2290        if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY))
2291                return db_release_key; // Only release key
2292        return db_release_nothing; // Release nothing
2293}
2294
2295/**
2296 * Returns the releaser that releases the specified release options.
2297 * @param which Options that specified what the releaser releases
2298 * @return Releaser for the specified release options
2299 * @public
2300 * @see #db_release_nothing(DBKey,void *,DBRelease)
2301 * @see #db_release_key(DBKey,void *,DBRelease)
2302 * @see #db_release_data(DBKey,void *,DBRelease)
2303 * @see #db_release_both(DBKey,void *,DBRelease)
2304 * @see #db_default_release(DBType,DBOptions)
2305 */
2306DBReleaser db_custom_release(DBRelease which)
2307{
2308        DB_COUNTSTAT(db_custom_release);
2309        switch (which) {
2310                case DB_RELEASE_NOTHING: return db_release_nothing;
2311                case DB_RELEASE_KEY:     return db_release_key;
2312                case DB_RELEASE_DATA:    return db_release_data;
2313                case DB_RELEASE_BOTH:    return db_release_both;
2314                default:
2315                        ShowError("db_custom_release: Unknown release options %u\n", which);
2316                        return NULL;
2317        }
2318}
2319
2320/**
2321 * Allocate a new database of the specified type.
2322 * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)}
2323 * before creating the database.
2324 * @param file File where the database is being allocated
2325 * @param line Line of the file where the database is being allocated
2326 * @param type Type of database
2327 * @param options Options of the database
2328 * @param maxlen Maximum length of the string to be used as key in string
2329 *          databases
2330 * @return The interface of the database
2331 * @public
2332 * @see #DBMap_impl
2333 * @see #db_fix_options(DBType,DBOptions)
2334 */
2335DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen)
2336{
2337        DBMap_impl* db;
2338        unsigned int i;
2339
2340#ifdef DB_ENABLE_STATS
2341        DB_COUNTSTAT(db_alloc);
2342        switch (type) {
2343                case DB_INT: DB_COUNTSTAT(db_int_alloc); break;
2344                case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break;
2345                case DB_STRING: DB_COUNTSTAT(db_string_alloc); break;
2346                case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break;
2347        }
2348#endif /* DB_ENABLE_STATS */
2349        CREATE(db, struct DBMap_impl, 1);
2350
2351        options = db_fix_options(type, options);
2352        /* Interface of the database */
2353        db->vtable.iterator = db_obj_iterator;
2354        db->vtable.get      = db_obj_get;
2355        db->vtable.getall   = db_obj_getall;
2356        db->vtable.vgetall  = db_obj_vgetall;
2357        db->vtable.ensure   = db_obj_ensure;
2358        db->vtable.vensure  = db_obj_vensure;
2359        db->vtable.put      = db_obj_put;
2360        db->vtable.remove   = db_obj_remove;
2361        db->vtable.foreach  = db_obj_foreach;
2362        db->vtable.vforeach = db_obj_vforeach;
2363        db->vtable.clear    = db_obj_clear;
2364        db->vtable.vclear   = db_obj_vclear;
2365        db->vtable.destroy  = db_obj_destroy;
2366        db->vtable.vdestroy = db_obj_vdestroy;
2367        db->vtable.size     = db_obj_size;
2368        db->vtable.type     = db_obj_type;
2369        db->vtable.options  = db_obj_options;
2370        /* File and line of allocation */
2371        db->alloc_file = file;
2372        db->alloc_line = line;
2373        /* Lock system */
2374        db->free_list = NULL;
2375        db->free_count = 0;
2376        db->free_max = 0;
2377        db->free_lock = 0;
2378        /* Other */
2379        db->nodes = ers_new(sizeof(struct dbn));
2380        db->cmp = db_default_cmp(type);
2381        db->hash = db_default_hash(type);
2382        db->release = db_default_release(type, options);
2383        for (i = 0; i < HASH_SIZE; i++)
2384                db->ht[i] = NULL;
2385        db->cache = NULL;
2386        db->type = type;
2387        db->options = options;
2388        db->item_count = 0;
2389        db->maxlen = maxlen;
2390        db->global_lock = 0;
2391
2392        return &db->vtable;
2393}
2394
2395#ifdef DB_MANUAL_CAST_TO_UNION
2396/**
2397 * Manual cast from 'int' to the union DBKey.
2398 * Created for compilers that don't support casting to unions.
2399 * @param key Key to be casted
2400 * @return The key as a DBKey union
2401 * @public
2402 * @see #DB_MANUAL_CAST_TO_UNION
2403 */
2404DBKey db_i2key(int key)
2405{
2406        DBKey ret;
2407
2408        DB_COUNTSTAT(db_i2key);
2409        ret.i = key;
2410        return ret;
2411}
2412
2413/**
2414 * Manual cast from 'unsigned int' to the union DBKey.
2415 * Created for compilers that don't support casting to unions.
2416 * @param key Key to be casted
2417 * @return The key as a DBKey union
2418 * @public
2419 * @see #DB_MANUAL_CAST_TO_UNION
2420 */
2421DBKey db_ui2key(unsigned int key)
2422{
2423        DBKey ret;
2424
2425        DB_COUNTSTAT(db_ui2key);
2426        ret.ui = key;
2427        return ret;
2428}
2429
2430/**
2431 * Manual cast from 'const char *' to the union DBKey.
2432 * Created for compilers that don't support casting to unions.
2433 * @param key Key to be casted
2434 * @return The key as a DBKey union
2435 * @public
2436 * @see #DB_MANUAL_CAST_TO_UNION
2437 */
2438DBKey db_str2key(const char *key)
2439{
2440        DBKey ret;
2441
2442        DB_COUNTSTAT(db_str2key);
2443        ret.str = key;
2444        return ret;
2445}
2446#endif /* DB_MANUAL_CAST_TO_UNION */
2447
2448/**
2449 * Initializes the database system.
2450 * @public
2451 * @see #db_final(void)
2452 */
2453void db_init(void)
2454{
2455        DB_COUNTSTAT(db_init);
2456}
2457
2458/**
2459 * Finalizes the database system.
2460 * @public
2461 * @see #db_init(void)
2462 */
2463void db_final(void)
2464{
2465#ifdef DB_ENABLE_STATS
2466        DB_COUNTSTAT(db_final);
2467        ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n"
2468                        "allocated %u, freed %u\n",
2469                        stats.db_node_alloc, stats.db_node_free);
2470        ShowInfo(CL_WHITE"Database types"CL_RESET":\n"
2471                        "DB_INT     : allocated %10u, destroyed %10u\n"
2472                        "DB_UINT    : allocated %10u, destroyed %10u\n"
2473                        "DB_STRING  : allocated %10u, destroyed %10u\n"
2474                        "DB_ISTRING : allocated %10u, destroyed %10u\n",
2475                        stats.db_int_alloc,     stats.db_int_destroy,
2476                        stats.db_uint_alloc,    stats.db_uint_destroy,
2477                        stats.db_string_alloc,  stats.db_string_destroy,
2478                        stats.db_istring_alloc, stats.db_istring_destroy);
2479        ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n"
2480                        "db_rotate_left     %10u, db_rotate_right    %10u,\n"
2481                        "db_rebalance       %10u, db_rebalance_erase %10u,\n"
2482                        "db_is_key_null     %10u,\n"
2483                        "db_dup_key         %10u, db_dup_key_free    %10u,\n"
2484                        "db_free_add        %10u, db_free_remove     %10u,\n"
2485                        "db_free_lock       %10u, db_free_unlock     %10u,\n"
2486                        "db_int_cmp         %10u, db_uint_cmp        %10u,\n"
2487                        "db_string_cmp      %10u, db_istring_cmp     %10u,\n"
2488                        "db_int_hash        %10u, db_uint_hash       %10u,\n"
2489                        "db_string_hash     %10u, db_istring_hash    %10u,\n"
2490                        "db_release_nothing %10u, db_release_key     %10u,\n"
2491                        "db_release_data    %10u, db_release_both    %10u,\n"
2492                        "dbit_first         %10u, dbit_last          %10u,\n"
2493                        "dbit_next          %10u, dbit_prev          %10u,\n"
2494                        "dbit_exists        %10u, dbit_remove        %10u,\n"
2495                        "dbit_destroy       %10u, db_iterator        %10u,\n"
2496                        "db_get             %10u,\n"
2497                        "db_getall          %10u, db_vgetall         %10u,\n"
2498                        "db_ensure          %10u, db_vensure         %10u,\n"
2499                        "db_put             %10u, db_remove          %10u,\n"
2500                        "db_foreach         %10u, db_vforeach        %10u,\n"
2501                        "db_clear           %10u, db_vclear          %10u,\n"
2502                        "db_destroy         %10u, db_vdestroy        %10u,\n"
2503                        "db_size            %10u, db_type            %10u,\n"
2504                        "db_options         %10u, db_fix_options     %10u,\n"
2505                        "db_default_cmp     %10u, db_default_hash    %10u,\n"
2506                        "db_default_release %10u, db_custom_release  %10u,\n"
2507                        "db_alloc           %10u, db_i2key           %10u,\n"
2508                        "db_ui2key          %10u, db_str2key         %10u,\n"
2509                        "db_init            %10u, db_final           %10u\n",
2510                        stats.db_rotate_left,     stats.db_rotate_right,
2511                        stats.db_rebalance,       stats.db_rebalance_erase,
2512                        stats.db_is_key_null,
2513                        stats.db_dup_key,         stats.db_dup_key_free,
2514                        stats.db_free_add,        stats.db_free_remove,
2515                        stats.db_free_lock,       stats.db_free_unlock,
2516                        stats.db_int_cmp,         stats.db_uint_cmp,
2517                        stats.db_string_cmp,      stats.db_istring_cmp,
2518                        stats.db_int_hash,        stats.db_uint_hash,
2519                        stats.db_string_hash,     stats.db_istring_hash,
2520                        stats.db_release_nothing, stats.db_release_key,
2521                        stats.db_release_data,    stats.db_release_both,
2522                        stats.dbit_first,         stats.dbit_last,
2523                        stats.dbit_next,          stats.dbit_prev,
2524                        stats.dbit_exists,        stats.dbit_remove,
2525                        stats.dbit_destroy,       stats.db_iterator,
2526                        stats.db_get,
2527                        stats.db_getall,          stats.db_vgetall,
2528                        stats.db_ensure,          stats.db_vensure,
2529                        stats.db_put,             stats.db_remove,
2530                        stats.db_foreach,         stats.db_vforeach,
2531                        stats.db_clear,           stats.db_vclear,
2532                        stats.db_destroy,         stats.db_vdestroy,
2533                        stats.db_size,            stats.db_type,
2534                        stats.db_options,         stats.db_fix_options,
2535                        stats.db_default_cmp,     stats.db_default_hash,
2536                        stats.db_default_release, stats.db_custom_release,
2537                        stats.db_alloc,           stats.db_i2key,
2538                        stats.db_ui2key,          stats.db_str2key,
2539                        stats.db_init,            stats.db_final);
2540#endif /* DB_ENABLE_STATS */
2541}
2542
2543// Link DB System - jAthena
2544void linkdb_insert( struct linkdb_node** head, void *key, void* data)
2545{
2546        struct linkdb_node *node;
2547        if( head == NULL ) return ;
2548        node = (struct linkdb_node*)aMalloc( sizeof(struct linkdb_node) );
2549        if( *head == NULL ) {
2550                // first node
2551                *head      = node;
2552                node->prev = NULL;
2553                node->next = NULL;
2554        } else {
2555                // link nodes
2556                node->next    = *head;
2557                node->prev    = (*head)->prev;
2558                (*head)->prev = node;
2559                (*head)       = node;
2560        }
2561        node->key  = key;
2562        node->data = data;
2563}
2564
2565void* linkdb_search( struct linkdb_node** head, void *key)
2566{
2567        int n = 0;
2568        struct linkdb_node *node;
2569        if( head == NULL ) return NULL;
2570        node = *head;
2571        while( node ) {
2572                if( node->key == key ) {
2573                        if( node->prev && n > 5 ) {
2574                                // ˆ—Œø—Љü‘P‚ׂ̈Éhead‚Ɉړ®‚³‚¹‚é
2575                                if(node->prev) node->prev->next = node->next;
2576                                if(node->next) node->next->prev = node->prev;
2577                                node->next = *head;
2578                                node->prev = (*head)->prev;
2579                                (*head)->prev = node;
2580                                (*head)       = node;
2581                        }
2582                        return node->data;
2583                }
2584                node = node->next;
2585                n++;
2586        }
2587        return NULL;
2588}
2589
2590void* linkdb_erase( struct linkdb_node** head, void *key)
2591{
2592        struct linkdb_node *node;
2593        if( head == NULL ) return NULL;
2594        node = *head;
2595        while( node ) {
2596                if( node->key == key ) {
2597                        void *data = node->data;
2598                        if( node->prev == NULL )
2599                                *head = node->next;
2600                        else
2601                                node->prev->next = node->next;
2602                        if( node->next )
2603                                node->next->prev = node->prev;
2604                        aFree( node );
2605                        return data;
2606                }
2607                node = node->next;
2608        }
2609        return NULL;
2610}
2611
2612void linkdb_replace( struct linkdb_node** head, void *key, void *data )
2613{
2614        int n = 0;
2615        struct linkdb_node *node;
2616        if( head == NULL ) return ;
2617        node = *head;
2618        while( node ) {
2619                if( node->key == key ) {
2620                        if( node->prev && n > 5 ) {
2621                                // ˆ—Œø—Љü‘P‚ׂ̈Éhead‚Ɉړ®‚³‚¹‚é
2622                                if(node->prev) node->prev->next = node->next;
2623                                if(node->next) node->next->prev = node->prev;
2624                                node->next = *head;
2625                                node->prev = (*head)->prev;
2626                                (*head)->prev = node;
2627                                (*head)       = node;
2628                        }
2629                        node->data = data;
2630                        return ;
2631                }
2632                node = node->next;
2633                n++;
2634        }
2635        // Œ©‚‚©‚ç‚È‚¢‚̂ő}“ü
2636        linkdb_insert( head, key, data );
2637}
2638
2639void linkdb_final( struct linkdb_node** head )
2640{
2641        struct linkdb_node *node, *node2;
2642        if( head == NULL ) return ;
2643        node = *head;
2644        while( node ) {
2645                node2 = node->next;
2646                aFree( node );
2647                node = node2;
2648        }
2649        *head = NULL;
2650}
Note: See TracBrowser for help on using the browser.