⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tdb.c

📁 经典的ppp程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (dbuf.dsize != rec.data_len) {		/* update size */		rec.data_len = dbuf.dsize;		ret = rec_write(tdb, rec_ptr, &rec);	} else		ret = 0; out:	tdb_unlock(tdb, BUCKET(hash));	return ret;}/* find an entry in the database given a key */TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key){	unsigned hash;	tdb_off rec_ptr;	struct list_struct rec;	TDB_DATA ret = null_data;        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_fetch() called with null context\n");#endif            return null_data;        }	/* find which hash bucket it is in */	hash = tdb_hash(&key);	tdb_lock(tdb, BUCKET(hash));	rec_ptr = tdb_find(tdb, key, hash, &rec);	if (rec_ptr) {		ret.dptr = tdb_alloc_read(tdb,					  rec_ptr + sizeof(rec) + rec.key_len,					  rec.data_len);		ret.dsize = rec.data_len;	}		tdb_unlock(tdb, BUCKET(hash));	return ret;}/* check if an entry in the database exists    note that 1 is returned if the key is found and 0 is returned if not found   this doesn't match the conventions in the rest of this module, but is   compatible with gdbm*/int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key){	unsigned hash;	tdb_off rec_ptr;	struct list_struct rec;	        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_exists() called with null context\n");#endif            return 0;        }	/* find which hash bucket it is in */	hash = tdb_hash(&key);	tdb_lock(tdb, BUCKET(hash));	rec_ptr = tdb_find(tdb, key, hash, &rec);	tdb_unlock(tdb, BUCKET(hash));	return rec_ptr != 0;}/* traverse the entire database - calling fn(tdb, key, data) on each element.   return -1 on error or the record count traversed   if fn is NULL then it is not called   a non-zero return value from fn() indicates that the traversal should stop  */int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void* state), void* state){	int count = 0;	unsigned h;	tdb_off offset, rec_ptr;	struct list_struct rec;	char *data;	TDB_DATA key, dbuf;        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_traverse() called with null context\n");#endif            return -1;        }	/* loop over all hash chains */	for (h = 0; h < tdb->header.hash_size; h++) {		tdb_lock(tdb, BUCKET(h));		/* read in the hash top */		offset = tdb_hash_top(tdb, h);		if (ofs_read(tdb, offset, &rec_ptr) == -1) {			goto fail;		}		/* traverse all records for this hash */		while (rec_ptr) {			if (rec_read(tdb, rec_ptr, &rec) == -1) {				goto fail;			}			/* now read the full record */			data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), 					     rec.key_len + rec.data_len);			if (!data) {				goto fail;			}			key.dptr = data;			key.dsize = rec.key_len;			dbuf.dptr = data + rec.key_len;			dbuf.dsize = rec.data_len;			count++;			if (fn && fn(tdb, key, dbuf, state) != 0) {				/* they want us to stop traversing */				free(data);				tdb_unlock(tdb, BUCKET(h));				return count;			}			/* a miss - drat */			free(data);			/* move to the next record */			rec_ptr = rec.next;		}		tdb_unlock(tdb, BUCKET(h));	}	/* return the number traversed */	return count; fail:	tdb_unlock(tdb, BUCKET(h));	return -1;}/* find the first entry in the database and return its key */TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb){	tdb_off offset, rec_ptr;	struct list_struct rec;	unsigned hash;	TDB_DATA ret;        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_firstkey() called with null context\n");#endif            return null_data;        }	/* look for a non-empty hash chain */	for (hash = 0, rec_ptr = 0; 	     hash < tdb->header.hash_size;	     hash++) {		/* find the top of the hash chain */		offset = tdb_hash_top(tdb, hash);		tdb_lock(tdb, BUCKET(hash));		/* read in the hash top */		if (ofs_read(tdb, offset, &rec_ptr) == -1) {			goto fail;		}		if (rec_ptr) break;		tdb_unlock(tdb, BUCKET(hash));	}	if (rec_ptr == 0) return null_data;	/* we've found a non-empty chain, now read the record */	if (rec_read(tdb, rec_ptr, &rec) == -1) {		goto fail;	}	/* allocate and read the key space */	ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);	ret.dsize = rec.key_len;	tdb_unlock(tdb, BUCKET(hash));	return ret; fail:	tdb_unlock(tdb, BUCKET(hash));	return null_data;}/* find the next entry in the database, returning its key */TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key){	unsigned hash, hbucket;	tdb_off rec_ptr, offset;	struct list_struct rec;	TDB_DATA ret;        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_nextkey() called with null context\n");#endif            return null_data;        }	/* find which hash bucket it is in */	hash = tdb_hash(&key);	hbucket = BUCKET(hash);		tdb_lock(tdb, hbucket);	rec_ptr = tdb_find(tdb, key, hash, &rec);	if (rec_ptr) {		/* we want the next record after this one */		rec_ptr = rec.next;	}	/* not found or last in hash: look for next non-empty hash chain */	while (rec_ptr == 0) {		tdb_unlock(tdb, hbucket);		if (++hbucket >= tdb->header.hash_size - 1)			return null_data;		offset = tdb_hash_top(tdb, hbucket);		tdb_lock(tdb, hbucket);		/* read in the hash top */		if (ofs_read(tdb, offset, &rec_ptr) == -1) {			tdb_unlock(tdb, hbucket);			return null_data;		}	}	/* Read the record. */	if (rec_read(tdb, rec_ptr, &rec) == -1) {		tdb_unlock(tdb, hbucket);		return null_data;	}	/* allocate and read the key */	ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);	ret.dsize = rec.key_len;	tdb_unlock(tdb, hbucket);	return ret;}/* delete an entry in the database given a key */int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key){	unsigned hash;	tdb_off offset, rec_ptr, last_ptr;	struct list_struct rec, lastrec;	char *data = NULL;        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_delete() called with null context\n");#endif            return -1;        }	/* find which hash bucket it is in */	hash = tdb_hash(&key);	tdb_lock(tdb, BUCKET(hash));	/* find the top of the hash chain */	offset = tdb_hash_top(tdb, hash);	/* read in the hash top */	if (ofs_read(tdb, offset, &rec_ptr) == -1) {		goto fail;	}	last_ptr = 0;	/* keep looking until we find the right record */	while (rec_ptr) {		if (rec_read(tdb, rec_ptr, &rec) == -1) {			goto fail;		}		if (hash == rec.full_hash && key.dsize == rec.key_len) {			/* a very likely hit - read the record and full key */			data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), 					     rec.key_len);			if (!data) {				goto fail;			}			if (memcmp(key.dptr, data, key.dsize) == 0) {				/* a definite match - delete it */				if (last_ptr == 0) {					offset = tdb_hash_top(tdb, hash);					if (ofs_write(tdb, offset, &rec.next) == -1) {						goto fail;					}				} else {					lastrec.next = rec.next;					if (rec_write(tdb, last_ptr, &lastrec) == -1) {						goto fail;					}									}				tdb_unlock(tdb, BUCKET(hash));				tdb_lock(tdb, -1);				/* and recover the space */				offset = FREELIST_TOP;				if (ofs_read(tdb, offset, &rec.next) == -1) {					goto fail2;				}				rec.magic = TDB_FREE_MAGIC;				if (rec_write(tdb, rec_ptr, &rec) == -1) {					goto fail2;				}				if (ofs_write(tdb, offset, &rec_ptr) == -1) {					goto fail2;				}				/* yipee - all done */				free(data);				tdb_unlock(tdb, -1);				return 0;			}			/* a miss - drat */			free(data);			data = NULL;		}		/* move to the next record */		last_ptr = rec_ptr;		lastrec = rec;		rec_ptr = rec.next;	} fail:	if (data) free(data);	tdb_unlock(tdb, BUCKET(hash));	return -1; fail2:	if (data) free(data);	tdb_unlock(tdb, -1);	return -1;}/* store an element in the database, replacing any existing element   with the same key    return 0 on success, -1 on failure*/int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag){	struct list_struct rec;	unsigned hash;	tdb_off rec_ptr, offset;	char *p = NULL;        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_store() called with null context\n");#endif            return -1;        }	/* find which hash bucket it is in */	hash = tdb_hash(&key);	/* check for it existing */	if (flag == TDB_INSERT && tdb_exists(tdb, key)) {		tdb->ecode = TDB_ERR_EXISTS;		return -1;	}	/* first try in-place update */	if (flag != TDB_INSERT && tdb_update(tdb, key, dbuf) == 0) {		return 0;	}	rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize);	if (rec_ptr == 0) {		return -1;	}	tdb_lock(tdb, BUCKET(hash));	/* delete any existing record - if it doesn't exist we don't care */	if (flag != TDB_INSERT) {		tdb_delete(tdb, key);	}	/* read the newly created record */	if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {		goto fail;	}	if (rec.magic != TDB_FREE_MAGIC) goto fail;	/* find the top of the hash chain */	offset = tdb_hash_top(tdb, hash);	/* read in the hash top diretcly into our next pointer */	if (ofs_read(tdb, offset, &rec.next) == -1) {		goto fail;	}	rec.key_len = key.dsize;	rec.data_len = dbuf.dsize;	rec.full_hash = hash;	rec.magic = TDB_MAGIC;	p = (char *)malloc(sizeof(rec) + key.dsize + dbuf.dsize);	if (!p) {		tdb->ecode = TDB_ERR_OOM;		goto fail;	}	memcpy(p, &rec, sizeof(rec));	memcpy(p+sizeof(rec), key.dptr, key.dsize);	memcpy(p+sizeof(rec)+key.dsize, dbuf.dptr, dbuf.dsize);	if (tdb_write(tdb, rec_ptr, p, sizeof(rec)+key.dsize+dbuf.dsize) == -1)		goto fail;	free(p); 	p = NULL;	/* and point the top of the hash chain at it */	if (ofs_write(tdb, offset, &rec_ptr) == -1) goto fail;	tdb_unlock(tdb, BUCKET(hash));	return 0; fail:#if TDB_DEBUG	printf("store failed for hash 0x%08x in bucket %u\n", hash, BUCKET(hash));#endif	if (p) free(p);	tdb_unlock(tdb, BUCKET(hash));	return -1;}/* open the database, creating it if necessary    The open_flags and mode are passed straight to the open call on the database   file. A flags value of O_WRONLY is invalid   The hash size is advisory, use zero for a default value.    return is NULL on error*/TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,		      int open_flags, mode_t mode){	TDB_CONTEXT tdb, *ret;	struct stat st;	memset(&tdb, 0, sizeof(tdb));	tdb.fd = -1;	tdb.name = NULL;	tdb.map_ptr = NULL;	if ((open_flags & O_ACCMODE) == O_WRONLY) {		goto fail;	}	if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;	tdb.read_only = ((open_flags & O_ACCMODE) == O_RDONLY);        if (name != NULL) {            tdb.fd = open(name, open_flags, mode);            if (tdb.fd == -1) {		goto fail;            }        }	/* ensure there is only one process initialising at once */	tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW);		if (tdb_flags & TDB_CLEAR_IF_FIRST) {		/* we need to zero the database if we are the only		   one with it open */		if (tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) {			ftruncate(tdb.fd, 0);			tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK);		}	}	/* leave this lock in place */	tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW);	if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) ||	    strcmp(tdb.header.magic_food, TDB_MAGIC_FOOD) != 0 ||	    tdb.header.version != TDB_VERSION) {		/* its not a valid database - possibly initialise it */		if (!(open_flags & O_CREAT)) {			goto fail;		}		if (tdb_new_database(&tdb, hash_size) == -1) goto fail;		lseek(tdb.fd, 0, SEEK_SET);		if (tdb.fd != -1 && read(tdb.fd, &tdb.header,                                          sizeof(tdb.header)) !=                                          sizeof(tdb.header))                     goto fail;	}        if (tdb.fd != -1) {            fstat(tdb.fd, &st);            /* map the database and fill in the return structure */            tdb.name = (char *)strdup(name);            tdb.map_size = st.st_size;        }        tdb.locked = (int *)calloc(tdb.header.hash_size+1,                                    sizeof(tdb.locked[0]));        if (!tdb.locked) {            goto fail;        }#if HAVE_MMAP        if (tdb.fd != -1) {            tdb.map_ptr = (void *)mmap(NULL, st.st_size,                                        tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE,                                       MAP_SHARED | MAP_FILE, tdb.fd, 0);        }#endif	ret = (TDB_CONTEXT *)malloc(sizeof(tdb));	if (!ret) goto fail;	*ret = tdb;#if TDB_DEBUG	printf("mapped database of hash_size %u map_size=%u\n", 	       hash_size, tdb.map_size);#endif	tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLKW);	return ret; fail:        if (tdb.name) free(tdb.name);	if (tdb.fd != -1) close(tdb.fd);	if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size);	return NULL;}/* close a database */int tdb_close(TDB_CONTEXT *tdb){	if (!tdb) return -1;	if (tdb->name) free(tdb->name);	if (tdb->fd != -1) close(tdb->fd);	if (tdb->locked) free(tdb->locked);	if (tdb->map_ptr) {            if (tdb->fd != -1) {                munmap(tdb->map_ptr, tdb->map_size);            } else {                free(tdb->map_ptr);            }        }	memset(tdb, 0, sizeof(*tdb));	free(tdb);	return 0;}/* lock the database. If we already have it locked then don't do anything */int tdb_writelock(TDB_CONTEXT *tdb){        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_writelock() called with null context\n");#endif            return -1;        }	return tdb_lock(tdb, -1);}/* unlock the database. */int tdb_writeunlock(TDB_CONTEXT *tdb){        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_writeunlock() called with null context\n");#endif            return -1;        }	return tdb_unlock(tdb, -1);}/* lock one hash chain. This is meant to be used to reduce locking   contention - it cannot guarantee how many records will be locked */int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key){        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_lockchain() called with null context\n");#endif            return -1;        }	return tdb_lock(tdb, BUCKET(tdb_hash(&key)));}/* unlock one hash chain */int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key){        if (tdb == NULL) {#ifdef TDB_DEBUG            printf("tdb_unlockchain() called with null context\n");#endif            return -1;        }	return tdb_unlock(tdb, BUCKET(tdb_hash(&key)));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -