hash: allow caching of hash value
parent
4562f44f9b
commit
f1985b03bd
|
@ -41,6 +41,7 @@ int apk_blob_spn(apk_blob_t blob, const char *accept, apk_blob_t *l, apk_blob_t
|
|||
int apk_blob_cspn(apk_blob_t blob, const char *reject, apk_blob_t *l, apk_blob_t *r);
|
||||
int apk_blob_split(apk_blob_t blob, apk_blob_t split, apk_blob_t *l, apk_blob_t *r);
|
||||
int apk_blob_rsplit(apk_blob_t blob, char split, apk_blob_t *l, apk_blob_t *r);
|
||||
unsigned long apk_blob_hash_seed(apk_blob_t, unsigned long seed);
|
||||
unsigned long apk_blob_hash(apk_blob_t str);
|
||||
int apk_blob_compare(apk_blob_t a, apk_blob_t b);
|
||||
unsigned int apk_blob_parse_uint(apk_blob_t *b, int radix);
|
||||
|
|
|
@ -38,6 +38,7 @@ struct apk_db_file {
|
|||
struct apk_db_dir {
|
||||
apk_hash_node hash_node;
|
||||
|
||||
unsigned int hash;
|
||||
struct hlist_head files;
|
||||
struct apk_db_dir *parent;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
||||
*/
|
||||
|
@ -48,8 +48,36 @@ void apk_hash_init(struct apk_hash *h, const struct apk_hash_ops *ops,
|
|||
void apk_hash_free(struct apk_hash *h);
|
||||
|
||||
int apk_hash_foreach(struct apk_hash *h, apk_hash_enumerator_f e, void *ctx);
|
||||
apk_hash_item apk_hash_get(struct apk_hash *h, apk_blob_t key);
|
||||
void apk_hash_insert(struct apk_hash *h, apk_hash_item item);
|
||||
void apk_hash_delete(struct apk_hash *h, apk_blob_t key);
|
||||
apk_hash_item apk_hash_get_hashed(struct apk_hash *h, apk_blob_t key, unsigned long hash);
|
||||
void apk_hash_insert_hashed(struct apk_hash *h, apk_hash_item item, unsigned long hash);
|
||||
void apk_hash_delete_hashed(struct apk_hash *h, apk_blob_t key, unsigned long hash);
|
||||
|
||||
static inline unsigned long apk_hash_from_key(struct apk_hash *h, apk_blob_t key)
|
||||
{
|
||||
return h->ops->hash_key(key);
|
||||
}
|
||||
|
||||
static inline unsigned long apk_hash_from_item(struct apk_hash *h, apk_hash_item item)
|
||||
{
|
||||
if (h->ops->hash_item != NULL)
|
||||
return h->ops->hash_item(item);
|
||||
return apk_hash_from_key(h, h->ops->get_key(item));
|
||||
}
|
||||
|
||||
static inline apk_hash_item apk_hash_get(struct apk_hash *h, apk_blob_t key)
|
||||
{
|
||||
return apk_hash_get_hashed(h, key, apk_hash_from_key(h, key));
|
||||
}
|
||||
|
||||
|
||||
static inline void apk_hash_insert(struct apk_hash *h, apk_hash_item item)
|
||||
{
|
||||
return apk_hash_insert_hashed(h, item, apk_hash_from_item(h, item));
|
||||
}
|
||||
|
||||
static inline void apk_hash_delete(struct apk_hash *h, apk_blob_t key)
|
||||
{
|
||||
return apk_hash_delete_hashed(h, key, apk_hash_from_key(h, key));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -98,9 +98,9 @@ int apk_blob_split(apk_blob_t blob, apk_blob_t split, apk_blob_t *l, apk_blob_t
|
|||
}
|
||||
}
|
||||
|
||||
unsigned long apk_blob_hash(apk_blob_t blob)
|
||||
unsigned long apk_blob_hash_seed(apk_blob_t blob, unsigned long seed)
|
||||
{
|
||||
unsigned long hash = 5381;
|
||||
unsigned long hash = seed;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < blob.len; i++)
|
||||
|
@ -109,6 +109,11 @@ unsigned long apk_blob_hash(apk_blob_t blob)
|
|||
return hash;
|
||||
}
|
||||
|
||||
unsigned long apk_blob_hash(apk_blob_t blob)
|
||||
{
|
||||
return apk_blob_hash_seed(blob, 5381);
|
||||
}
|
||||
|
||||
int apk_blob_compare(apk_blob_t a, apk_blob_t b)
|
||||
{
|
||||
if (a.len == b.len)
|
||||
|
|
|
@ -101,6 +101,7 @@ static const struct apk_hash_ops dir_hash_ops = {
|
|||
};
|
||||
|
||||
struct apk_db_file_hash_key {
|
||||
unsigned long dirhash;
|
||||
apk_blob_t dirname;
|
||||
apk_blob_t filename;
|
||||
};
|
||||
|
@ -109,16 +110,14 @@ static unsigned long apk_db_file_hash_key(apk_blob_t _key)
|
|||
{
|
||||
struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
|
||||
|
||||
return apk_blob_hash(key->dirname) ^
|
||||
apk_blob_hash(key->filename);
|
||||
return apk_blob_hash_seed(key->filename, key->dirhash);
|
||||
}
|
||||
|
||||
static unsigned long apk_db_file_hash_item(apk_hash_item item)
|
||||
{
|
||||
struct apk_db_file *dbf = (struct apk_db_file *) item;
|
||||
|
||||
return apk_blob_hash(APK_BLOB_STR(dbf->diri->dir->dirname)) ^
|
||||
apk_blob_hash(APK_BLOB_STR(dbf->filename));
|
||||
return apk_blob_hash_seed(APK_BLOB_STR(dbf->filename), dbf->diri->dir->hash);
|
||||
}
|
||||
|
||||
static int apk_db_file_compare_item(apk_hash_item item, apk_blob_t _key)
|
||||
|
@ -127,6 +126,9 @@ static int apk_db_file_compare_item(apk_hash_item item, apk_blob_t _key)
|
|||
struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
|
||||
int r;
|
||||
|
||||
if (key->dirhash != dbf->diri->dir->hash)
|
||||
return key->dirhash - dbf->diri->dir->hash;
|
||||
|
||||
r = apk_blob_compare(key->dirname, APK_BLOB_STR(dbf->diri->dir->dirname));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
@ -150,8 +152,9 @@ struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name)
|
|||
struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name)
|
||||
{
|
||||
struct apk_name *pn;
|
||||
unsigned long hash = apk_hash_from_key(&db->available.names, name);
|
||||
|
||||
pn = apk_db_query_name(db, name);
|
||||
pn = (struct apk_name *) apk_hash_get_hashed(&db->available.names, name, hash);
|
||||
if (pn != NULL)
|
||||
return pn;
|
||||
|
||||
|
@ -161,7 +164,7 @@ struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name)
|
|||
|
||||
pn->name = apk_blob_cstr(name);
|
||||
pn->id = db->name_id++;
|
||||
apk_hash_insert(&db->available.names, pn);
|
||||
apk_hash_insert_hashed(&db->available.names, pn, hash);
|
||||
|
||||
return pn;
|
||||
}
|
||||
|
@ -195,12 +198,13 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
|
|||
{
|
||||
struct apk_db_dir *dir;
|
||||
apk_blob_t bparent;
|
||||
unsigned long hash = apk_hash_from_key(&db->installed.dirs, name);
|
||||
int i;
|
||||
|
||||
if (name.len && name.ptr[name.len-1] == '/')
|
||||
name.len--;
|
||||
|
||||
dir = apk_db_dir_query(db, name);
|
||||
dir = (struct apk_db_dir *) apk_hash_get_hashed(&db->installed.dirs, name, hash);
|
||||
if (dir != NULL)
|
||||
return apk_db_dir_ref(dir);
|
||||
|
||||
|
@ -210,7 +214,8 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
|
|||
dir->refs = 1;
|
||||
memcpy(dir->dirname, name.ptr, name.len);
|
||||
dir->dirname[name.len] = 0;
|
||||
apk_hash_insert(&db->installed.dirs, dir);
|
||||
dir->hash = apk_blob_hash(APK_BLOB_STR(dir->dirname));
|
||||
apk_hash_insert_hashed(&db->installed.dirs, dir, hash);
|
||||
|
||||
if (name.len == 0)
|
||||
dir->parent = NULL;
|
||||
|
@ -286,6 +291,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
|
|||
struct apk_db_file_hash_key key;
|
||||
|
||||
key = (struct apk_db_file_hash_key) {
|
||||
.dirhash = apk_blob_hash(dir),
|
||||
.dirname = dir,
|
||||
.filename = name,
|
||||
};
|
||||
|
|
19
src/hash.c
19
src/hash.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
||||
*/
|
||||
|
@ -43,15 +43,14 @@ int apk_hash_foreach(struct apk_hash *h, apk_hash_enumerator_f e, void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
apk_hash_item apk_hash_get(struct apk_hash *h, apk_blob_t key)
|
||||
apk_hash_item apk_hash_get_hashed(struct apk_hash *h, apk_blob_t key, unsigned long hash)
|
||||
{
|
||||
ptrdiff_t offset = h->ops->node_offset;
|
||||
unsigned long hash;
|
||||
apk_hash_node *pos;
|
||||
apk_hash_item item;
|
||||
apk_blob_t itemkey;
|
||||
|
||||
hash = h->ops->hash_key(key) % h->buckets->num;
|
||||
hash %= h->buckets->num;
|
||||
if (h->ops->compare_item != NULL) {
|
||||
hlist_for_each(pos, &h->buckets->item[hash]) {
|
||||
item = ((void *) pos) - offset;
|
||||
|
@ -70,30 +69,24 @@ apk_hash_item apk_hash_get(struct apk_hash *h, apk_blob_t key)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void apk_hash_insert(struct apk_hash *h, apk_hash_item item)
|
||||
void apk_hash_insert_hashed(struct apk_hash *h, apk_hash_item item, unsigned long hash)
|
||||
{
|
||||
unsigned long hash;
|
||||
apk_hash_node *node;
|
||||
|
||||
if (h->ops->hash_item == NULL)
|
||||
hash = h->ops->hash_key(h->ops->get_key(item));
|
||||
else
|
||||
hash = h->ops->hash_item(item);
|
||||
hash %= h->buckets->num;
|
||||
node = (apk_hash_node *) (item + h->ops->node_offset);
|
||||
hlist_add_head(node, &h->buckets->item[hash]);
|
||||
h->num_items++;
|
||||
}
|
||||
|
||||
void apk_hash_delete(struct apk_hash *h, apk_blob_t key)
|
||||
void apk_hash_delete_hashed(struct apk_hash *h, apk_blob_t key, unsigned long hash)
|
||||
{
|
||||
ptrdiff_t offset = h->ops->node_offset;
|
||||
unsigned long hash;
|
||||
apk_hash_node *pos;
|
||||
apk_hash_item item;
|
||||
apk_blob_t itemkey;
|
||||
|
||||
hash = h->ops->hash_key(key) % h->buckets->num;
|
||||
hash %= h->buckets->num;
|
||||
if (h->ops->compare_item != NULL) {
|
||||
hlist_for_each(pos, &h->buckets->item[hash]) {
|
||||
item = ((void *) pos) - offset;
|
||||
|
|
Loading…
Reference in New Issue