From b5267523b67fbb77deacd7e9b44110a31086805d Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Thu, 21 Dec 2006 02:32:51 +0000 Subject: - Added a 1-node cache to db. Removed party_cache and guild_cache since now the database has a cache. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9545 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/db.c | 164 +++++++++++++++++++++++++++++--------------------------- src/map/guild.c | 18 +++---- src/map/party.c | 32 +++++------ 3 files changed, 104 insertions(+), 110 deletions(-) (limited to 'src') diff --git a/src/common/db.c b/src/common/db.c index 306d713dd..87b6e7c4f 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -1,68 +1,68 @@ /*****************************************************************************\ - * Copyright (c) Athena Dev Teams - Licensed under GNU GPL * - * For more information, see LICENCE in the main folder * - * * - * This file is separated in five sections: * - * (1) Private typedefs, enums, structures, defines and gblobal variables * - * (2) Private functions * - * (3) Protected functions used internally * - * (4) Protected functions used in the interface of the database * - * (5) Public functions * - * * - * The databases are structured as a hashtable of RED-BLACK trees. * - * * - * Properties of the RED-BLACK trees being used: * - * 1. The value of any node is greater than the value of its left child and * - * less than the value of its right child. * - * 2. Every node is colored either RED or BLACK. * - * 3. Every red node that is not a leaf has only black children. * - * 4. Every path from the root to a leaf contains the same number of black * - * nodes. * - * 5. The root node is black. * - * An n node in a RED-BLACK tree has the property that its * - * height is O(lg(n)). * - * Another important property is that after adding a node to a RED-BLACK * - * tree, the tree can be readjusted in O(lg(n)) time. * - * Similarly, after deleting a node from a RED-BLACK tree, the tree can be * - * readjusted in O(lg(n)) time. * - * {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/} * - * * - * How to add new database types: * - * 1. Add the identifier of the new database type to the enum DBType * - * 2. If not already there, add the data type of the key to the union DBKey * - * 3. If the key can be considered NULL, update the function db_is_key_null * - * 4. If the key can be duplicated, update the functions db_dup_key and * - * db_dup_key_free * - * 5. Create a comparator and update the function db_default_cmp * - * 6. Create a hasher and update the function db_default_hash * - * 7. If the new database type requires or does not support some options, * - * update the function db_fix_options * - * * - * TODO: * - * - create test cases to test the database system thoroughly * - * - make data an enumeration * - * - finish this header describing the database system * - * - create custom database allocator * - * - make the system thread friendly * - * - change the structure of the database to T-Trees * - * - create a db that organizes itself by splaying * - * * - * HISTORY: * - * 2.1 (Athena build #???#) - Portability fix * - * - Fixed the portability of casting to union and added the functions * - * {@link DB#ensure(DB,DBKey,DBCreateData,...)} and * - * {@link DB#clear(DB,DBApply,...)}. * - * 2.0 (Athena build 4859) - Transition version * - * - Almost everything recoded with a strategy similar to objects, * - * database structure is maintained. * - * 1.0 (up to Athena build 4706) * - * - Previous database system. * - * * - * @version 2.1 (Athena build #???#) - Portability fix * - * @author (Athena build 4859) Flavio @ Amazon Project * - * @author (up to Athena build 4706) Athena Dev Teams * - * @encoding US-ASCII * - * @see common#db.h * + * Copyright (c) Athena Dev Teams - Licensed under GNU GPL + * For more information, see LICENCE in the main folder + * + * This file is separated in five sections: + * (1) Private typedefs, enums, structures, defines and gblobal variables + * (2) Private functions + * (3) Protected functions used internally + * (4) Protected functions used in the interface of the database + * (5) Public functions + * + * The databases are structured as a hashtable of RED-BLACK trees. + * + * Properties of the RED-BLACK trees being used: + * 1. The value of any node is greater than the value of its left child and + * less than the value of its right child. + * 2. Every node is colored either RED or BLACK. + * 3. Every red node that is not a leaf has only black children. + * 4. Every path from the root to a leaf contains the same number of black + * nodes. + * 5. The root node is black. + * An n node in a RED-BLACK tree has the property that its + * height is O(lg(n)). + * Another important property is that after adding a node to a RED-BLACK + * tree, the tree can be readjusted in O(lg(n)) time. + * Similarly, after deleting a node from a RED-BLACK tree, the tree can be + * readjusted in O(lg(n)) time. + * {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/} + * + * How to add new database types: + * 1. Add the identifier of the new database type to the enum DBType + * 2. If not already there, add the data type of the key to the union DBKey + * 3. If the key can be considered NULL, update the function db_is_key_null + * 4. If the key can be duplicated, update the functions db_dup_key and + * db_dup_key_free + * 5. Create a comparator and update the function db_default_cmp + * 6. Create a hasher and update the function db_default_hash + * 7. If the new database type requires or does not support some options, + * update the function db_fix_options + * + * TODO: + * - create test cases to test the database system thoroughly + * - make data an enumeration + * - finish this header describing the database system + * - create custom database allocator + * - make the system thread friendly + * - change the structure of the database to T-Trees + * - create a db that organizes itself by splaying + * + * HISTORY: + * 2006/12/21 - Added 1-node cache to the database. + * 2.1 (Athena build #???#) - Portability fix + * - Fixed the portability of casting to union and added the functions + * {@link DB#ensure(DB,DBKey,DBCreateData,...)} and + * {@link DB#clear(DB,DBApply,...)}. + * 2.0 (Athena build 4859) - Transition version + * - Almost everything recoded with a strategy similar to objects, + * database structure is maintained. + * 1.0 (up to Athena build 4706) + * - Previous database system. + * + * @version 2006/12/21 + * @author Athena Dev team + * @encoding US-ASCII + * @see #db.h \*****************************************************************************/ #include #include @@ -182,9 +182,10 @@ typedef struct db { DBHasher hash; DBReleaser release; DBNode ht[HASH_SIZE]; + DBNode cache; DBType type; DBOptions options; - unsigned int item_count; + uint32 item_count; unsigned short maxlen; unsigned global_lock : 1; } *DB_impl; @@ -1129,6 +1130,9 @@ static void *db_obj_get(DB self, DBKey key) return NULL; // nullpo candidate } + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) + return db->cache->data; // cache hit + db_free_lock(db); node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; while (node) { @@ -1142,6 +1146,7 @@ static void *db_obj_get(DB self, DBKey key) else node = node->right; } + db->cache = node; db_free_unlock(db); return data; } @@ -1277,6 +1282,9 @@ static void *db_obj_vensure(DB self, DBKey key, DBCreateData create, va_list arg return NULL; // nullpo candidate } + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) + return db->cache->data; // cache hit + db_free_lock(db); hash = db->hash(key, db->maxlen)%HASH_SIZE; node = db->ht[hash]; @@ -1293,7 +1301,7 @@ static void *db_obj_vensure(DB self, DBKey key, DBCreateData create, va_list arg } // Create node if necessary if (node == NULL) { - if (db->item_count == (unsigned int)~0) { + if (db->item_count == UINT32_MAX) { ShowError("db_vensure: item_count overflow, aborting item insertion.\n" "Database allocated at %s:%d", db->alloc_file, db->alloc_line); @@ -1334,6 +1342,7 @@ static void *db_obj_vensure(DB self, DBKey key, DBCreateData create, va_list arg node->data = create(key, args); } data = node->data; + db->cache = node; db_free_unlock(db); return data; } @@ -1408,7 +1417,7 @@ static void *db_obj_put(DB self, DBKey key, void *data) return NULL; // nullpo candidate } - if (db->item_count == (unsigned int)~0) { + if (db->item_count == UINT32_MAX) { ShowError("db_put: item_count overflow, aborting item insertion.\n" "Database allocated at %s:%d", db->alloc_file, db->alloc_line); @@ -1471,6 +1480,7 @@ static void *db_obj_put(DB self, DBKey key, void *data) node->key = key; } node->data = data; + db->cache = node; db_free_unlock(db); return old_data; } @@ -1515,6 +1525,8 @@ static void *db_obj_remove(DB self, DBKey key) c = db->cmp(key, node->key, db->maxlen); if (c == 0) { if (!(node->deleted)) { + if (db->cache == node) + db->cache = NULL; data = node->data; db->release(node->key, node->data, DB_RELEASE_DATA); db_free_add(db, node, &db->ht[hash]); @@ -1641,6 +1653,7 @@ static int db_obj_vclear(DB self, DBApply func, va_list args) if (db == NULL) return 0; // nullpo candidate db_free_lock(db); + db->cache = NULL; for (i = 0; i < HASH_SIZE; i++) { // Apply the func and delete in the order: left tree, right tree, current node node = db->ht[i]; @@ -1750,18 +1763,10 @@ static int db_obj_vdestroy(DB self, DBApply func, va_list args) #ifdef DB_ENABLE_STATS switch (db->type) { - case DB_INT: - COUNT(db_int_destroy); - break; - case DB_UINT: - COUNT(db_uint_destroy); - break; - case DB_STRING: - COUNT(db_string_destroy); - break; - case DB_ISTRING: - COUNT(db_istring_destroy); - break; + case DB_INT: COUNT(db_int_destroy); break; + case DB_UINT: COUNT(db_uint_destroy); break; + case DB_STRING: COUNT(db_string_destroy); break; + case DB_ISTRING: COUNT(db_istring_destroy); break; } #endif /* DB_ENABLE_STATS */ db_free_lock(db); @@ -2110,6 +2115,7 @@ DB db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned db->release = db_default_release(type, options); for (i = 0; i < HASH_SIZE; i++) db->ht[i] = NULL; + db->cache = NULL; db->type = type; db->options = options; db->item_count = 0; diff --git a/src/map/guild.c b/src/map/guild.c index 0ddb966d5..a5db3664a 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -25,12 +25,11 @@ #include "skill.h" #include "log.h" -static struct guild* guild_cache; //For fast retrieval of the same guild over and over. [Skotlex] -static struct dbt *guild_db; -static struct dbt *castle_db; -static struct dbt *guild_expcache_db; -static struct dbt *guild_infoevent_db; -static struct dbt *guild_castleinfoevent_db; +static DB guild_db; +static DB castle_db; +static DB guild_expcache_db; +static DB guild_infoevent_db; +static DB guild_castleinfoevent_db; struct eventlist { char name[50]; @@ -225,10 +224,7 @@ void do_init_guild(void) // struct guild *guild_search(int guild_id) { - if(guild_cache && guild_cache->guild_id == guild_id) - return guild_cache; - guild_cache = idb_get(guild_db,guild_id); - return guild_cache; + return idb_get(guild_db,guild_id); } int guild_searchname_sub(DBKey key,void *data,va_list ap) { @@ -1576,8 +1572,6 @@ int guild_broken(int guild_id,int flag) guild_db->foreach(guild_db,guild_broken_sub,guild_id); castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id); - if (guild_cache && guild_cache->guild_id == guild_id) - guild_cache = NULL; guild_storage_delete(guild_id); idb_remove(guild_db,guild_id); return 0; diff --git a/src/map/party.c b/src/map/party.c index babc9129d..aabd336ff 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -22,8 +22,7 @@ #include "skill.h" #include "status.h" -static struct dbt* party_db; -static struct party_data* party_cache = NULL; //party in cache for skipping consecutive lookups. [Skotlex] +static DB party_db; int party_share_level = 10; int party_send_xy_timer(int tid,unsigned int tick,int id,int data); @@ -34,13 +33,13 @@ int party_send_xy_timer(int tid,unsigned int tick,int id,int data); */ static void party_fill_member(struct party_member *member, struct map_session_data *sd) { member->account_id = sd->status.account_id; - member->char_id = sd->status.char_id; - memcpy(member->name,sd->status.name,NAME_LENGTH); - member->class_ = sd->status.class_; - member->map = sd->mapindex; - member->lv = sd->status.base_level; - member->online = 1; - member->leader = 0; + member->char_id = sd->status.char_id; + memcpy(member->name, sd->status.name, NAME_LENGTH); + member->class_ = sd->status.class_; + member->map = sd->mapindex; + member->lv = sd->status.base_level; + member->online = 1; + member->leader = 0; } /*========================================== @@ -55,19 +54,16 @@ void do_final_party(void) void do_init_party(void) { party_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); - add_timer_func_list(party_send_xy_timer,"party_send_xy_timer"); - add_timer_interval(gettick()+battle_config.party_update_interval,party_send_xy_timer,0,0,battle_config.party_update_interval); + add_timer_func_list(party_send_xy_timer, "party_send_xy_timer"); + add_timer_interval(gettick()+battle_config.party_update_interval, party_send_xy_timer, 0, 0, battle_config.party_update_interval); } // struct party_data *party_search(int party_id) { - if(!party_id) return NULL; - if (party_cache && party_cache->party.party_id == party_id) - return party_cache; - - party_cache = idb_get(party_db,party_id); - return party_cache; + if(!party_id) + return NULL; + return idb_get(party_db,party_id); } int party_searchname_sub(DBKey key,void *data,va_list ap) { @@ -449,8 +445,6 @@ int party_broken(int party_id) p->data[i].sd->state.party_sent=0; } } - if (party_cache && party_cache->party.party_id == party_id) - party_cache = NULL; idb_remove(party_db,party_id); return 0; } -- cgit v1.2.3-70-g09d2