summaryrefslogtreecommitdiff
path: root/src/common/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/db.c')
-rw-r--r--src/common/db.c106
1 files changed, 90 insertions, 16 deletions
diff --git a/src/common/db.c b/src/common/db.c
index 9f2c75a68..5eb73c785 100644
--- a/src/common/db.c
+++ b/src/common/db.c
@@ -354,6 +354,29 @@ static void db_rebalance_erase(struct dbn *z,struct dbn **root)
}
}
+void db_free_lock(struct dbt *table) {
+ table->free_lock++;
+}
+
+void db_free_unlock(struct dbt *table) {
+ if(--table->free_lock == 0) {
+ int i;
+ for(i = 0; i < table->free_count ; i++) {
+ db_rebalance_erase(table->free_list[i].z,table->free_list[i].root);
+ if(table->cmp == strdb_cmp) {
+ free(table->free_list[i].z->key);
+ }
+#ifdef MALLOC_DBN
+ free_dbn(table->free_list[i].z);
+#else
+ free(table->free_list[i].z);
+#endif
+ table->item_count--;
+ }
+ table->free_count = 0;
+ }
+}
+
struct dbn* db_insert(struct dbt *table,void* key,void* data)
{
struct dbn *p,*priv;
@@ -363,10 +386,33 @@ struct dbn* db_insert(struct dbt *table,void* key,void* data)
for(c=0,priv=NULL ,p = table->ht[hash];p;){
c=table->cmp(table,key,p->key);
if(c==0){ // replace
- if (table->release)
- table->release(p, 3);
+ if (table->release)
+ table->release(p, 3);
+ if(p->deleted) {
+ // 削除されたデータなので、free_list 上の削除予定を消す
+ int i;
+ for(i = 0; i < table->free_count ; i++) {
+ if(table->free_list[i].z == p) {
+ memmove(
+ &table->free_list[i],
+ &table->free_list[i+1],
+ sizeof(struct db_free)*(table->free_count - i - 1)
+ );
+ break;
+ }
+ }
+ if(i == table->free_count || table->free_count <= 0) {
+ printf("db_insert: cannnot find deleted db node.\n");
+ } else {
+ table->free_count--;
+ if(table->cmp == strdb_cmp) {
+ free(p->key);
+ }
+ }
+ }
p->data=data;
p->key=key;
+ p->deleted = 0;
return p;
}
priv=p;
@@ -391,6 +437,7 @@ struct dbn* db_insert(struct dbt *table,void* key,void* data)
p->key = key;
p->data = data;
p->color = RED;
+ p->deleted = 0;
if(c==0){ // hash entry is empty
table->ht[hash] = p;
p->color = BLACK;
@@ -429,25 +476,47 @@ void* db_erase(struct dbt *table,void* key)
if(!p)
return NULL;
data=p->data;
- db_rebalance_erase(p,&table->ht[hash]);
-#ifdef MALLOC_DBN
- free_dbn(p);
-#else
- aFree(p);
-#endif
- table->item_count--;
+ if(table->free_lock) {
+ if(table->free_count == table->free_max) {
+ table->free_max += 32;
+ table->free_list = (struct db_free*)realloc(table->free_list,sizeof(struct db_free) * table->free_max);
+ }
+ table->free_list[table->free_count].z = p;
+ table->free_list[table->free_count].root = &table->ht[hash];
+ table->free_count++;
+ p->deleted = 1;
+ p->data = NULL;
+ if(table->cmp == strdb_cmp) {
+ if(table->maxlen) {
+ char *key = (char*)malloc(table->maxlen);
+ memcpy(key,p->key,table->maxlen);
+ p->key = key;
+ } else {
+ p->key = strdup((const char*)p->key);
+ }
+ }
+ } else {
+ db_rebalance_erase(p,&table->ht[hash]);
+ #ifdef MALLOC_DBN
+ free_dbn(p);
+ #else
+ aFree(p);
+ #endif
+ table->item_count--;
+ }
return data;
}
void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...)
{
int i,sp;
- int count = 0;
+ int count = table->item_count;
// red-black treeなので64個stackがあれば2^32個ノードまで大丈夫
struct dbn *p,*pn,*stack[64];
va_list ap;
va_start(ap,func);
+ db_free_lock(table);
for(i=0;i<HASH_SIZE;i++){
if((p=table->ht[i])==NULL)
continue;
@@ -457,8 +526,9 @@ void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...)
//if (!p->data) {
// printf("Warning: no data for key %d in db_foreach (db.c) !\n",(int)p->key);
//} else {
- func(p->key, p->data, ap);
- count++;
+ if(!p->deleted)
+ func(p->key, p->data, ap);
+ count--;
//}
if((pn=p->left)!=NULL){
if(p->right){
@@ -476,10 +546,11 @@ void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...)
}
}
}
- if(count != table->item_count) {
+ db_free_unlock(table);
+ if(count) {
printf(
- "db_foreach : data lost %d of %d item(s) allocated from %s line %d\n",
- table->item_count - count,count,table->alloc_file,table->alloc_line
+ "db_foreach : data lost %d item(s) allocated from %s line %d\n",
+ count,table->alloc_file,table->alloc_line
);
}
va_end(ap);
@@ -492,12 +563,13 @@ void db_final(struct dbt *table,int (*func)(void*,void*,va_list),...)
va_list ap;
va_start(ap,func);
+ db_free_lock(table);
for(i=0;i<HASH_SIZE;i++){
if((p=table->ht[i])==NULL)
continue;
sp=0;
while(1){
- if(func)
+ if(func && !p->deleted)
func(p->key,p->data,ap);
if((pn=p->left)!=NULL){
if(p->right){
@@ -520,6 +592,8 @@ void db_final(struct dbt *table,int (*func)(void*,void*,va_list),...)
p=pn;
}
}
+ db_free_unlock(table);
+ free(table->free_list);
aFree(table);
va_end(ap);
}