aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-partition-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-partition-table.c')
-rw-r--r--camel/camel-partition-table.c1015
1 files changed, 0 insertions, 1015 deletions
diff --git a/camel/camel-partition-table.c b/camel/camel-partition-table.c
deleted file mode 100644
index 68e0e257b5..0000000000
--- a/camel/camel-partition-table.c
+++ /dev/null
@@ -1,1015 +0,0 @@
-/*
- * Copyright (C) 2001 Ximian Inc.
- *
- * Authors: Michael Zucchi <notzed@ximian.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "e-util/e-msgport.h"
-
-#include "camel-block-file.h"
-#include "camel-partition-table.h"
-
-/* Do we synchronously write table updates - makes the
- tables consistent after program crash without sync */
-/*#define SYNC_UPDATES*/
-
-#ifdef ENABLE_THREADS
-#include <pthread.h>
-#endif
-
-#define d(x) /*(printf("%s(%d):%s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__),(x))*/
-/* key index debug */
-#define k(x) /*(printf("%s(%d):%s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__),(x))*/
-
-#ifdef ENABLE_THREADS
-
-struct _CamelPartitionTablePrivate {
- pthread_mutex_t lock; /* for locking partition */
-};
-
-#define CAMEL_PARTITION_TABLE_LOCK(kf, lock) (pthread_mutex_lock(&(kf)->priv->lock))
-#define CAMEL_PARTITION_TABLE_UNLOCK(kf, lock) (pthread_mutex_unlock(&(kf)->priv->lock))
-#else
-#define CAMEL_PARTITION_TABLE_LOCK(kf, lock)
-#define CAMEL_PARTITION_TABLE_UNLOCK(kf, lock)
-#endif
-
-static void
-camel_partition_table_class_init(CamelPartitionTableClass *klass)
-{
-}
-
-static void
-camel_partition_table_init(CamelPartitionTable *cpi)
-{
- struct _CamelPartitionTablePrivate *p;
-
- e_dlist_init(&cpi->partition);
-
- p = cpi->priv = g_malloc0(sizeof(*cpi->priv));
-#ifdef ENABLE_THREADS
- pthread_mutex_init(&p->lock, NULL);
-#endif
-}
-
-static void
-camel_partition_table_finalise(CamelPartitionTable *cpi)
-{
- CamelBlock *bl;
- struct _CamelPartitionTablePrivate *p;
-
- p = cpi->priv;
-
- if (cpi->blocks) {
- while ((bl = (CamelBlock *)e_dlist_remhead(&cpi->partition))) {
- camel_block_file_sync_block(cpi->blocks, bl);
- camel_block_file_unref_block(cpi->blocks, bl);
- }
- camel_block_file_sync(cpi->blocks);
-
- camel_object_unref((CamelObject *)cpi->blocks);
- }
-
-#ifdef ENABLE_THREADS
- pthread_mutex_destroy(&p->lock);
-#endif
- g_free(p);
-
-}
-
-CamelType
-camel_partition_table_get_type(void)
-{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- type = camel_type_register(camel_object_get_type(), "CamelPartitionTable",
- sizeof (CamelPartitionTable),
- sizeof (CamelPartitionTableClass),
- (CamelObjectClassInitFunc) camel_partition_table_class_init,
- NULL,
- (CamelObjectInitFunc) camel_partition_table_init,
- (CamelObjectFinalizeFunc) camel_partition_table_finalise);
- }
-
- return type;
-}
-
-/* ********************************************************************** */
-
-/*
- Have 2 hashes:
- Name -> nameid
- Word -> wordid
-
-nameid is pointer to name file, includes a bit to say if name is deleted
-wordid is a pointer to word file, includes pointer to start of word entries
-
-delete a name -> set it as deleted, do nothing else though
-
-lookup word, if nameid is deleted, mark it in wordlist as unused and mark for write (?)
-*/
-
-/* ********************************************************************** */
-
-/* This simple hash seems to work quite well */
-static camel_hash_t hash_key(const char *key)
-{
- camel_hash_t hash = 0xABADF00D;
-
- while (*key) {
- hash = hash * (*key) ^ (*key);
- key++;
- }
-
- return hash;
-}
-
-/* Call with lock held */
-static CamelBlock *find_partition(CamelPartitionTable *cpi, camel_hash_t id, int *indexp)
-{
- int index, jump;
- CamelBlock *bl;
- CamelPartitionMapBlock *ptb;
- CamelPartitionMap *part;
-
- /* first, find the block this key might be in, then binary search the block */
- bl = (CamelBlock *)cpi->partition.head;
- while (bl->next) {
- ptb = (CamelPartitionMapBlock *)&bl->data;
- part = ptb->partition;
- if (ptb->used > 0 && id <= part[ptb->used-1].hashid) {
- index = ptb->used/2;
- jump = ptb->used/4;
-
- if (jump == 0)
- jump = 1;
-
- while (1) {
- if (id <= part[index].hashid) {
- if (index == 0 || id > part[index-1].hashid)
- break;
- index -= jump;
- } else {
- if (index >= ptb->used-1)
- break;
- index += jump;
- }
- jump = jump/2;
- if (jump == 0)
- jump = 1;
- }
- *indexp = index;
-
- return bl;
- }
- bl = bl->next;
- }
-
- g_warning("could not find a partition that could fit ! partition table corrupt!");
-
- /* This should never be reached */
-
- return NULL;
-}
-
-CamelPartitionTable *camel_partition_table_new(struct _CamelBlockFile *bs, camel_block_t root)
-{
- CamelPartitionTable *cpi;
- CamelPartitionMapBlock *ptb;
- CamelPartitionKeyBlock *kb;
- CamelBlock *block, *pblock;
-
- cpi = (CamelPartitionTable *)camel_object_new(camel_partition_table_get_type());
- cpi->rootid = root;
- cpi->blocks = bs;
- camel_object_ref((CamelObject *)bs);
-
- /* read the partition table into memory */
- do {
- block = camel_block_file_get_block(bs, root);
- if (block == NULL)
- goto fail;
-
- ptb = (CamelPartitionMapBlock *)&block->data;
-
- d(printf("Adding partition block, used = %d, hashid = %08x\n", ptb->used, ptb->partition[0].hashid));
-
- /* if we have no data, prime initial block */
- if (ptb->used == 0 && e_dlist_empty(&cpi->partition) && ptb->next == 0) {
- pblock = camel_block_file_new_block(bs);
- if (pblock == NULL) {
- camel_block_file_unref_block(bs, block);
- goto fail;
- }
- kb = (CamelPartitionKeyBlock *)&pblock->data;
- kb->used = 0;
- ptb->used = 1;
- ptb->partition[0].hashid = 0xffffffff;
- ptb->partition[0].blockid = pblock->id;
- camel_block_file_touch_block(bs, pblock);
- camel_block_file_unref_block(bs, pblock);
- camel_block_file_touch_block(bs, block);
-#ifdef SYNC_UPDATES
- camel_block_file_sync_block(bs, block);
-#endif
- }
-
- root = ptb->next;
- camel_block_file_detach_block(bs, block);
- e_dlist_addtail(&cpi->partition, (EDListNode *)block);
- } while (root);
-
- return cpi;
-
-fail:
- camel_object_unref((CamelObject *)cpi);
- return NULL;
-}
-
-/* sync our blocks, the caller must still sync the blockfile itself */
-int
-camel_partition_table_sync(CamelPartitionTable *cpi)
-{
- CamelBlock *bl, *bn;
- struct _CamelPartitionTablePrivate *p;
- int ret = 0;
-
- CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
-
- p = cpi->priv;
-
- if (cpi->blocks) {
- bl = (CamelBlock *)cpi->partition.head;
- bn = bl->next;
- while (bn) {
- ret = camel_block_file_sync_block(cpi->blocks, bl);
- if (ret == -1)
- goto fail;
- bl = bn;
- bn = bn->next;
- }
- }
-fail:
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
-
- return ret;
-}
-
-camel_key_t camel_partition_table_lookup(CamelPartitionTable *cpi, const char *key)
-{
- CamelPartitionKeyBlock *pkb;
- CamelPartitionMapBlock *ptb;
- CamelBlock *block, *ptblock;
- camel_hash_t hashid;
- camel_key_t keyid = 0;
- int index, i;
-
- hashid = hash_key(key);
-
- CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
-
- ptblock = find_partition(cpi, hashid, &index);
- if (ptblock == NULL) {
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
- return 0;
- }
- ptb = (CamelPartitionMapBlock *)&ptblock->data;
- block = camel_block_file_get_block(cpi->blocks, ptb->partition[index].blockid);
- if (block == NULL) {
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
- return 0;
- }
-
- pkb = (CamelPartitionKeyBlock *)&block->data;
-
- /* What to do about duplicate hash's? */
- for (i=0;i<pkb->used;i++) {
- if (pkb->keys[i].hashid == hashid) {
- /* !! need to: lookup and compare string value */
- /* get_key() if key == key ... */
- keyid = pkb->keys[i].keyid;
- break;
- }
- }
-
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
-
- camel_block_file_unref_block(cpi->blocks, block);
-
- return keyid;
-}
-
-void camel_partition_table_remove(CamelPartitionTable *cpi, const char *key)
-{
- CamelPartitionKeyBlock *pkb;
- CamelPartitionMapBlock *ptb;
- CamelBlock *block, *ptblock;
- camel_hash_t hashid;
- camel_key_t keyid = 0;
- int index, i;
-
- hashid = hash_key(key);
-
- CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
-
- ptblock = find_partition(cpi, hashid, &index);
- if (ptblock == NULL) {
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
- return;
- }
- ptb = (CamelPartitionMapBlock *)&ptblock->data;
- block = camel_block_file_get_block(cpi->blocks, ptb->partition[index].blockid);
- if (block == NULL) {
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
- return;
- }
- pkb = (CamelPartitionKeyBlock *)&block->data;
-
- /* What to do about duplicate hash's? */
- for (i=0;i<pkb->used;i++) {
- if (pkb->keys[i].hashid == hashid) {
- /* !! need to: lookup and compare string value */
- /* get_key() if key == key ... */
- keyid = pkb->keys[i].keyid;
-
- /* remove this key */
- pkb->used--;
- for (;i<pkb->used;i++) {
- pkb->keys[i].keyid = pkb->keys[i+1].keyid;
- pkb->keys[i].hashid = pkb->keys[i+1].hashid;
- }
- camel_block_file_touch_block(cpi->blocks, block);
- break;
- }
- }
-
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
-
- camel_block_file_unref_block(cpi->blocks, block);
-}
-
-static int
-keys_cmp(const void *ap, const void *bp)
-{
- const CamelPartitionKey *a = ap;
- const CamelPartitionKey *b = bp;
-
- if (a->hashid < b->hashid)
- return -1;
- else if (a->hashid > b->hashid)
- return 1;
-
- return 0;
-}
-
-int
-camel_partition_table_add(CamelPartitionTable *cpi, const char *key, camel_key_t keyid)
-{
- camel_hash_t hashid, partid;
- int index, newindex = 0; /* initialisation of this and pkb/nkb is just to silence compiler */
- CamelPartitionMapBlock *ptb, *ptn;
- CamelPartitionKeyBlock *kb, *newkb, *nkb = NULL, *pkb = NULL;
- CamelBlock *block, *ptblock, *ptnblock;
- int i, half, len;
- struct _CamelPartitionKey keys[CAMEL_BLOCK_SIZE/4];
- int ret = -1;
-
-#define KEY_SIZE (sizeof(kb->keys)/sizeof(kb->keys[0]))
-
- hashid = hash_key(key);
-
- CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
- ptblock = find_partition(cpi, hashid, &index);
- if (ptblock == NULL) {
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
- return -1;
- }
- ptb = (CamelPartitionMapBlock *)&ptblock->data;
- block = camel_block_file_get_block(cpi->blocks, ptb->partition[index].blockid);
- if (block == NULL) {
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
- return -1;
- }
- kb = (CamelPartitionKeyBlock *)&block->data;
-
- /* TODO: Keep the key array in sorted order, cheaper lookups and split operation */
-
- if (kb->used < sizeof(kb->keys)/sizeof(kb->keys[0])) {
- /* Have room, just put it in */
- kb->keys[kb->used].hashid = hashid;
- kb->keys[kb->used].keyid = keyid;
- kb->used++;
- } else {
- CamelBlock *newblock = NULL, *nblock = NULL, *pblock = NULL;
-
- /* Need to split? See if previous or next has room, then split across that instead */
-
- /* TODO: Should look at next/previous partition table block as well ... */
-
- if (index > 0) {
- pblock = camel_block_file_get_block(cpi->blocks, ptb->partition[index-1].blockid);
- if (pblock == NULL)
- goto fail;
- pkb = (CamelPartitionKeyBlock *)&pblock->data;
- }
- if (index < (ptb->used-1)) {
- nblock = camel_block_file_get_block(cpi->blocks, ptb->partition[index+1].blockid);
- if (nblock == NULL) {
- if (pblock)
- camel_block_file_unref_block(cpi->blocks, pblock);
- goto fail;
- }
- nkb = (CamelPartitionKeyBlock *)&nblock->data;
- }
-
- if (pblock && pkb->used < KEY_SIZE) {
- if (nblock && nkb->used < KEY_SIZE) {
- if (pkb->used < nkb->used) {
- newindex = index+1;
- newblock = nblock;
- } else {
- newindex = index-1;
- newblock = pblock;
- }
- } else {
- newindex = index-1;
- newblock = pblock;
- }
- } else {
- if (nblock && nkb->used < KEY_SIZE) {
- newindex = index+1;
- newblock = nblock;
- }
- }
-
- /* We had no room, need to split across another block */
- if (newblock == NULL) {
- /* See if we have room in the partition table for this block or need to split that too */
- if (ptb->used >= sizeof(ptb->partition)/sizeof(ptb->partition[0])) {
- /* TODO: Could check next block to see if it'll fit there first */
- ptnblock = camel_block_file_new_block(cpi->blocks);
- if (ptnblock == NULL) {
- if (nblock)
- camel_block_file_unref_block(cpi->blocks, nblock);
- if (pblock)
- camel_block_file_unref_block(cpi->blocks, pblock);
- goto fail;
- }
- camel_block_file_detach_block(cpi->blocks, ptnblock);
-
- /* split block and link on-disk, always sorted */
- ptn = (CamelPartitionMapBlock *)&ptnblock->data;
- ptn->next = ptb->next;
- ptb->next = ptnblock->id;
- len = ptb->used / 2;
- ptn->used = ptb->used - len;
- ptb->used = len;
- memcpy(ptn->partition, &ptb->partition[len], ptn->used * sizeof(ptb->partition[0]));
-
- /* link in-memory */
- ptnblock->next = ptblock->next;
- ptblock->next->prev = ptnblock;
- ptblock->next = ptnblock;
- ptnblock->prev = ptblock;
-
- /* write in right order to ensure structure */
- camel_block_file_touch_block(cpi->blocks, ptnblock);
-#ifdef SYNC_UPDATES
- camel_block_file_sync_block(cpi->blocks, ptnblock);
-#endif
- if (index > len) {
- camel_block_file_touch_block(cpi->blocks, ptblock);
-#ifdef SYNC_UPDATES
- camel_block_file_sync_block(cpi->blocks, ptblock);
-#endif
- index -= len;
- ptb = ptn;
- ptblock = ptnblock;
- }
- }
-
- /* try get newblock before modifying existing */
- newblock = camel_block_file_new_block(cpi->blocks);
- if (newblock == NULL) {
- if (nblock)
- camel_block_file_unref_block(cpi->blocks, nblock);
- if (pblock)
- camel_block_file_unref_block(cpi->blocks, pblock);
- goto fail;
- }
-
- for (i=ptb->used-1;i>index;i--) {
- ptb->partition[i+1].hashid = ptb->partition[i].hashid;
- ptb->partition[i+1].blockid = ptb->partition[i].blockid;
- }
- ptb->used++;
-
- newkb = (CamelPartitionKeyBlock *)&newblock->data;
- newkb->used = 0;
- newindex = index+1;
-
- ptb->partition[newindex].hashid = ptb->partition[index].hashid;
- ptb->partition[newindex].blockid = newblock->id;
-
- if (nblock)
- camel_block_file_unref_block(cpi->blocks, nblock);
- if (pblock)
- camel_block_file_unref_block(cpi->blocks, pblock);
- } else {
- newkb = (CamelPartitionKeyBlock *)&newblock->data;
-
- if (newblock == pblock) {
- if (nblock)
- camel_block_file_unref_block(cpi->blocks, nblock);
- } else {
- if (pblock)
- camel_block_file_unref_block(cpi->blocks, pblock);
- }
- }
-
- /* sort keys to find midpoint */
- len = kb->used;
- memcpy(keys, kb->keys, sizeof(kb->keys[0])*len);
- memcpy(keys+len, newkb->keys, sizeof(newkb->keys[0])*newkb->used);
- len += newkb->used;
- keys[len].hashid = hashid;
- keys[len].keyid = keyid;
- len++;
- qsort(keys, len, sizeof(keys[0]), keys_cmp);
-
- /* Split keys, fix partition table */
- half = len/2;
- partid = keys[half-1].hashid;
-
- if (index < newindex) {
- memcpy(kb->keys, keys, sizeof(keys[0])*half);
- kb->used = half;
- memcpy(newkb->keys, keys+half, sizeof(keys[0])*(len-half));
- newkb->used = len-half;
- ptb->partition[index].hashid = partid;
- } else {
- memcpy(newkb->keys, keys, sizeof(keys[0])*half);
- newkb->used = half;
- memcpy(kb->keys, keys+half, sizeof(keys[0])*(len-half));
- kb->used = len-half;
- ptb->partition[newindex].hashid = partid;
- }
-
- camel_block_file_touch_block(cpi->blocks, ptblock);
-#ifdef SYNC_UPDATES
- camel_block_file_sync_block(cpi->blocks, ptblock);
-#endif
- camel_block_file_touch_block(cpi->blocks, newblock);
- camel_block_file_unref_block(cpi->blocks, newblock);
- }
-
- camel_block_file_touch_block(cpi->blocks, block);
- camel_block_file_unref_block(cpi->blocks, block);
-
- ret = 0;
-fail:
- CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
-
- return ret;
-}
-
-/* ********************************************************************** */
-
-
-#ifdef ENABLE_THREADS
-
-struct _CamelKeyTablePrivate {
- pthread_mutex_t lock; /* for locking key */
-};
-
-#define CAMEL_KEY_TABLE_LOCK(kf, lock) (pthread_mutex_lock(&(kf)->priv->lock))
-#define CAMEL_KEY_TABLE_UNLOCK(kf, lock) (pthread_mutex_unlock(&(kf)->priv->lock))
-#else
-#define CAMEL_KEY_TABLE_LOCK(kf, lock)
-#define CAMEL_KEY_TABLE_UNLOCK(kf, lock)
-#endif
-
-static void
-camel_key_table_class_init(CamelKeyTableClass *klass)
-{
-}
-
-static void
-camel_key_table_init(CamelKeyTable *ki)
-{
- struct _CamelKeyTablePrivate *p;
-
- p = ki->priv = g_malloc0(sizeof(*ki->priv));
-#ifdef ENABLE_THREADS
- pthread_mutex_init(&p->lock, NULL);
-#endif
-}
-
-static void
-camel_key_table_finalise(CamelKeyTable *ki)
-{
- struct _CamelKeyTablePrivate *p;
-
- p = ki->priv;
-
- if (ki->blocks) {
- if (ki->root_block) {
- camel_block_file_sync_block(ki->blocks, ki->root_block);
- camel_block_file_unref_block(ki->blocks, ki->root_block);
- }
- camel_block_file_sync(ki->blocks);
- camel_object_unref((CamelObject *)ki->blocks);
- }
-
-#ifdef ENABLE_THREADS
- pthread_mutex_destroy(&p->lock);
-#endif
- g_free(p);
-
-}
-
-CamelType
-camel_key_table_get_type(void)
-{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- type = camel_type_register(camel_object_get_type(), "CamelKeyTable",
- sizeof (CamelKeyTable),
- sizeof (CamelKeyTableClass),
- (CamelObjectClassInitFunc) camel_key_table_class_init,
- NULL,
- (CamelObjectInitFunc) camel_key_table_init,
- (CamelObjectFinalizeFunc) camel_key_table_finalise);
- }
-
- return type;
-}
-
-
-CamelKeyTable *
-camel_key_table_new(CamelBlockFile *bs, camel_block_t root)
-{
- CamelKeyTable *ki;
-
- ki = (CamelKeyTable *)camel_object_new(camel_key_table_get_type());
-
- ki->blocks = bs;
- camel_object_ref((CamelObject *)bs);
- ki->rootid = root;
-
- ki->root_block = camel_block_file_get_block(bs, ki->rootid);
- if (ki->root_block == NULL) {
- camel_object_unref((CamelObject *)ki);
- ki = NULL;
- } else {
- camel_block_file_detach_block(bs, ki->root_block);
- ki->root = (CamelKeyRootBlock *)&ki->root_block->data;
-
- k(printf("Opening key index\n"));
- k(printf(" first %u\n last %u\n free %u\n", ki->root->first, ki->root->last, ki->root->free));
- }
-
- return ki;
-}
-
-int
-camel_key_table_sync(CamelKeyTable *ki)
-{
-#ifdef SYNC_UPDATES
- return 0;
-#else
- return camel_block_file_sync_block(ki->blocks, ki->root_block);
-#endif
-}
-
-camel_key_t
-camel_key_table_add(CamelKeyTable *ki, const char *key, camel_block_t data, unsigned int flags)
-{
- CamelBlock *last, *next;
- CamelKeyBlock *kblast, *kbnext;
- int len, left;
- unsigned int offset;
- camel_key_t keyid = 0;
-
- /* Maximum key size = 128 chars */
- len = strlen(key);
- if (len > CAMEL_KEY_TABLE_MAX_KEY)
- len = 128;
-
- CAMEL_KEY_TABLE_LOCK(ki, lock);
-
- if (ki->root->last == 0) {
- last = camel_block_file_new_block(ki->blocks);
- if (last == NULL)
- goto fail;
- ki->root->last = ki->root->first = last->id;
- camel_block_file_touch_block(ki->blocks, ki->root_block);
- k(printf("adding first block, first = %u\n", ki->root->first));
- } else {
- last = camel_block_file_get_block(ki->blocks, ki->root->last);
- if (last == NULL)
- goto fail;
- }
-
- kblast = (CamelKeyBlock *)&last->data;
-
- if (kblast->used >= 127)
- goto fail;
-
- if (kblast->used > 0) {
- /*left = &kblast->u.keydata[kblast->u.keys[kblast->used-1].offset] - (char *)(&kblast->u.keys[kblast->used+1]);*/
- left = kblast->u.keys[kblast->used-1].offset - sizeof(kblast->u.keys[0])*(kblast->used+1);
- d(printf("key '%s' used = %d (%d), filled = %d, left = %d len = %d?\n",
- key, kblast->used, kblast->used * sizeof(kblast->u.keys[0]),
- sizeof(kblast->u.keydata) - kblast->u.keys[kblast->used-1].offset,
- left, len));
- if (left < len) {
- next = camel_block_file_new_block(ki->blocks);
- if (next == NULL) {
- camel_block_file_unref_block(ki->blocks, last);
- goto fail;
- }
- kbnext = (CamelKeyBlock *)&next->data;
- kblast->next = next->id;
- ki->root->last = next->id;
- d(printf("adding new block, first = %u, last = %u\n", ki->root->first, ki->root->last));
- camel_block_file_touch_block(ki->blocks, ki->root_block);
- camel_block_file_touch_block(ki->blocks, last);
- camel_block_file_unref_block(ki->blocks, last);
- kblast = kbnext;
- last = next;
- }
- }
-
- if (kblast->used > 0)
- offset = kblast->u.keys[kblast->used-1].offset - len;
- else
- offset = sizeof(kblast->u.keydata)-len;
-
- kblast->u.keys[kblast->used].flags = flags;
- kblast->u.keys[kblast->used].data = data;
- kblast->u.keys[kblast->used].offset = offset;
- memcpy(kblast->u.keydata + offset, key, len);
-
- keyid = (last->id & (~(CAMEL_BLOCK_SIZE-1))) | kblast->used;
-
- kblast->used++;
-
- g_assert(kblast->used < 127);
-
- camel_block_file_touch_block(ki->blocks, last);
- camel_block_file_unref_block(ki->blocks, last);
-
-#ifdef SYNC_UPDATES
- camel_block_file_sync_block(ki->blocks, ki->root_block);
-#endif
-fail:
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
-
- return keyid;
-}
-
-void
-camel_key_table_set_data(CamelKeyTable *ki, camel_key_t keyid, camel_block_t data)
-{
- CamelBlock *bl;
- camel_block_t blockid;
- int index;
- CamelKeyBlock *kb;
-
- if (keyid == 0)
- return;
-
- blockid = keyid & (~(CAMEL_BLOCK_SIZE-1));
- index = keyid & (CAMEL_BLOCK_SIZE-1);
-
- bl = camel_block_file_get_block(ki->blocks, blockid);
- if (bl == NULL)
- return;
- kb = (CamelKeyBlock *)&bl->data;
-
- CAMEL_KEY_TABLE_LOCK(ki, lock);
-
- if (kb->u.keys[index].data != data) {
- kb->u.keys[index].data = data;
- camel_block_file_touch_block(ki->blocks, bl);
- }
-
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
-
- camel_block_file_unref_block(ki->blocks, bl);
-}
-
-void
-camel_key_table_set_flags(CamelKeyTable *ki, camel_key_t keyid, unsigned int flags, unsigned int set)
-{
- CamelBlock *bl;
- camel_block_t blockid;
- int index;
- CamelKeyBlock *kb;
- unsigned int old;
-
- if (keyid == 0)
- return;
-
- blockid = keyid & (~(CAMEL_BLOCK_SIZE-1));
- index = keyid & (CAMEL_BLOCK_SIZE-1);
-
- bl = camel_block_file_get_block(ki->blocks, blockid);
- if (bl == NULL)
- return;
- kb = (CamelKeyBlock *)&bl->data;
-
- g_assert(kb->used < 127);
- g_assert(index < kb->used);
-
- CAMEL_KEY_TABLE_LOCK(ki, lock);
-
- old = kb->u.keys[index].flags;
- if ((old & set) != (flags & set)) {
- kb->u.keys[index].flags = (old & (~set)) | (flags & set);
- camel_block_file_touch_block(ki->blocks, bl);
- }
-
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
-
- camel_block_file_unref_block(ki->blocks, bl);
-}
-
-camel_block_t
-camel_key_table_lookup(CamelKeyTable *ki, camel_key_t keyid, char **keyp, unsigned int *flags)
-{
- CamelBlock *bl;
- camel_block_t blockid;
- int index, len, off;
- char *key;
- CamelKeyBlock *kb;
-
- if (keyp)
- *keyp = 0;
- if (flags)
- *flags = 0;
- if (keyid == 0)
- return 0;
-
- blockid = keyid & (~(CAMEL_BLOCK_SIZE-1));
- index = keyid & (CAMEL_BLOCK_SIZE-1);
-
- bl = camel_block_file_get_block(ki->blocks, blockid);
- if (bl == NULL)
- return 0;
-
- kb = (CamelKeyBlock *)&bl->data;
-
-#if 1
- g_assert(kb->used < 127); /* this should be more accurate */
- g_assert(index < kb->used);
-#else
- if (kb->used >=127 || index >= kb->used) {
- g_warning("Block %x: Invalid index or content: index %d used %d\n", blockid, index, kb->used);
- return 0;
- }
-#endif
-
- CAMEL_KEY_TABLE_LOCK(ki, lock);
-
- blockid = kb->u.keys[index].data;
- if (flags)
- *flags = kb->u.keys[index].flags;
-
- if (keyp) {
- off = kb->u.keys[index].offset;
- if (index == 0)
- len = sizeof(kb->u.keydata) - off;
- else
- len = kb->u.keys[index-1].offset - off;
- *keyp = key = g_malloc(len+1);
- memcpy(key, kb->u.keydata + off, len);
- key[len] = 0;
- }
-
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
-
- camel_block_file_unref_block(ki->blocks, bl);
-
- return blockid;
-}
-
-/* iterate through all keys */
-camel_key_t
-camel_key_table_next(CamelKeyTable *ki, camel_key_t next, char **keyp, unsigned int *flagsp, camel_block_t *datap)
-{
- CamelBlock *bl;
- CamelKeyBlock *kb;
- camel_block_t blockid;
- int index;
-
- if (keyp)
- *keyp = 0;
- if (flagsp)
- *flagsp = 0;
- if (datap)
- *datap = 0;
-
- CAMEL_KEY_TABLE_LOCK(ki, lock);
-
- if (next == 0) {
- next = ki->root->first;
- if (next == 0)
- return 0;
- } else
- next++;
-
- do {
- blockid = next & (~(CAMEL_BLOCK_SIZE-1));
- index = next & (CAMEL_BLOCK_SIZE-1);
-
- bl = camel_block_file_get_block(ki->blocks, blockid);
- if (bl == NULL) {
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
- return 0;
- }
-
- kb = (CamelKeyBlock *)&bl->data;
-
- /* see if we need to goto the next block */
- if (index >= kb->used) {
- /* FIXME: check for loops */
- next = kb->next;
- camel_block_file_unref_block(ki->blocks, bl);
- bl = NULL;
- }
- } while (bl == NULL);
-
- /* invalid block data */
- if ((kb->u.keys[index].offset >= sizeof(kb->u.keydata)
- /*|| kb->u.keys[index].offset < kb->u.keydata - (char *)&kb->u.keys[kb->used])*/
- || kb->u.keys[index].offset < sizeof(kb->u.keys[0]) * kb->used
- || (index > 0 &&
- (kb->u.keys[index-1].offset >= sizeof(kb->u.keydata)
- /*|| kb->u.keys[index-1].offset < kb->u.keydata - (char *)&kb->u.keys[kb->used]))) {*/
- || kb->u.keys[index-1].offset < sizeof(kb->u.keys[0]) * kb->used)))) {
- g_warning("Block %u invalid scanning keys", bl->id);
- camel_block_file_unref_block(ki->blocks, bl);
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
- return 0;
- }
-
- if (datap)
- *datap = kb->u.keys[index].data;
-
- if (flagsp)
- *flagsp = kb->u.keys[index].flags;
-
- if (keyp) {
- int len, off = kb->u.keys[index].offset;
- char *key;
-
- if (index == 0)
- len = sizeof(kb->u.keydata) - off;
- else
- len = kb->u.keys[index-1].offset - off;
- *keyp = key = g_malloc(len+1);
- memcpy(key, kb->u.keydata + off, len);
- key[len] = 0;
- }
-
- CAMEL_KEY_TABLE_UNLOCK(ki, lock);
-
- camel_block_file_unref_block(ki->blocks, bl);
-
- return next;
-}
-
-/* ********************************************************************** */