Ver código fonte

- Added a 1-node cache to db. Removed party_cache and guild_cache since now the database has a cache.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@9545 54d463be-8e91-2dee-dedb-b68131a5f0ec
FlavioJS 18 anos atrás
pai
commit
a2021e550b
4 arquivos alterados com 106 adições e 110 exclusões
  1. 2 0
      Changelog-Trunk.txt
  2. 85 79
      src/common/db.c
  3. 6 12
      src/map/guild.c
  4. 13 19
      src/map/party.c

+ 2 - 0
Changelog-Trunk.txt

@@ -4,6 +4,8 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2006/12/21
+	* Added a 1-node cache to db. Removed party_cache and guild_cache since 
+	  now the database has a cache.
 	* Fixed "warning: comparison is always false due to limited range of data type"
 	  by restricting script words to ASCII characters only.
 	* Moved md5calc to common. [FlavioJS]

+ 85 - 79
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.          *
- *                                                                           *
- *  <B>Properties of the RED-BLACK trees being used:</B>                     *
- *  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 <code>n</code> node in a RED-BLACK tree has the property that its     *
- *  height is <code>O(lg(n))</code>.                                         *
- *  Another important property is that after adding a node to a RED-BLACK    *
- *  tree, the tree can be readjusted in <code>O(lg(n))</code> time.          *
- *  Similarly, after deleting a node from a RED-BLACK tree, the tree can be  *
- *  readjusted in <code>O(lg(n))</code> time.                                *
- *  {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/}          *
- *                                                                           *
- *  <B>How to add new database types:</B>                                    *
- *  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.
+ *
+ *  <B>Properties of the RED-BLACK trees being used:</B>
+ *  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 <code>n</code> node in a RED-BLACK tree has the property that its
+ *  height is <code>O(lg(n))</code>.
+ *  Another important property is that after adding a node to a RED-BLACK
+ *  tree, the tree can be readjusted in <code>O(lg(n))</code> time.
+ *  Similarly, after deleting a node from a RED-BLACK tree, the tree can be
+ *  readjusted in <code>O(lg(n))</code> time.
+ *  {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/}
+ *
+ *  <B>How to add new database types:</B>
+ *  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 <stdio.h>
 #include <stdlib.h>
@@ -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;

+ 6 - 12
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;

+ 13 - 19
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;
 }