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

📄 tdb.c

📁 samba服务器!
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (tdb->max_dead_records != 0) {		/*		 * Allow for some dead records per hash chain, mainly for		 * tdb's with a very high create/delete rate like locking.tdb.		 */		if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)			return -1;		if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {			/*			 * Don't let the per-chain freelist grow too large,			 * delete all existing dead records			 */			tdb_purge_dead(tdb, hash);		}		if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {			tdb_unlock(tdb, BUCKET(hash), F_WRLCK);			return -1;		}		/*		 * Just mark the record as dead.		 */		rec.magic = TDB_DEAD_MAGIC;		ret = tdb_rec_write(tdb, rec_ptr, &rec);	}	else {		if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,						   &rec)))			return -1;		ret = tdb_do_delete(tdb, rec_ptr, &rec);	}	if (ret == 0) {		tdb_increment_seqnum(tdb);	}	if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)		TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));	return ret;}int tdb_delete(struct tdb_context *tdb, TDB_DATA key){	u32 hash = tdb->hash_fn(&key);	return tdb_delete_hash(tdb, key, hash);}/* * See if we have a dead record around with enough space */static tdb_off_t tdb_find_dead(struct tdb_context *tdb, u32 hash,			       struct list_struct *r, tdb_len_t length){	tdb_off_t rec_ptr;		/* read in the hash top */	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)		return 0;	/* keep looking until we find the right record */	while (rec_ptr) {		if (tdb_rec_read(tdb, rec_ptr, r) == -1)			return 0;		if (TDB_DEAD(r) && r->rec_len >= length) {			/*			 * First fit for simple coding, TODO: change to best			 * fit			 */			return rec_ptr;		}		rec_ptr = r->next;	}	return 0;}/* store an element in the database, replacing any existing element   with the same key    return 0 on success, -1 on failure*/int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag){	struct list_struct rec;	u32 hash;	tdb_off_t rec_ptr;	char *p = NULL;	int ret = -1;	if (tdb->read_only || tdb->traverse_read) {		tdb->ecode = TDB_ERR_RDONLY;		return -1;	}	/* find which hash bucket it is in */	hash = tdb->hash_fn(&key);	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)		return -1;	/* check for it existing, on insert. */	if (flag == TDB_INSERT) {		if (tdb_exists_hash(tdb, key, hash)) {			tdb->ecode = TDB_ERR_EXISTS;			goto fail;		}	} else {		/* first try in-place update, on modify or replace. */		if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {			goto done;		}		if (tdb->ecode == TDB_ERR_NOEXIST &&		    flag == TDB_MODIFY) {			/* if the record doesn't exist and we are in TDB_MODIFY mode then			 we should fail the store */			goto fail;		}	}	/* reset the error code potentially set by the tdb_update() */	tdb->ecode = TDB_SUCCESS;	/* delete any existing record - if it doesn't exist we don't           care.  Doing this first reduces fragmentation, and avoids           coalescing with `allocated' block before it's updated. */	if (flag != TDB_INSERT)		tdb_delete_hash(tdb, key, hash);	/* Copy key+value *before* allocating free space in case malloc	   fails and we are left with a dead spot in the tdb. */	if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {		tdb->ecode = TDB_ERR_OOM;		goto fail;	}	memcpy(p, key.dptr, key.dsize);	if (dbuf.dsize)		memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);	if (tdb->max_dead_records != 0) {		/*		 * Allow for some dead records per hash chain, look if we can		 * find one that can hold the new record. We need enough space		 * for key, data and tailer. If we find one, we don't have to		 * consult the central freelist.		 */		rec_ptr = tdb_find_dead(			tdb, hash, &rec,			key.dsize + dbuf.dsize + sizeof(tdb_off_t));		if (rec_ptr != 0) {			rec.key_len = key.dsize;			rec.data_len = dbuf.dsize;			rec.full_hash = hash;			rec.magic = TDB_MAGIC;			if (tdb_rec_write(tdb, rec_ptr, &rec) == -1			    || tdb->methods->tdb_write(				    tdb, rec_ptr + sizeof(rec),				    p, key.dsize + dbuf.dsize) == -1) {				goto fail;			}			goto done;		}	}	/*	 * We have to allocate some space from the freelist, so this means we	 * have to lock it. Use the chance to purge all the DEAD records from	 * the hash chain under the freelist lock.	 */	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {		goto fail;	}	if ((tdb->max_dead_records != 0)	    && (tdb_purge_dead(tdb, hash) == -1)) {		tdb_unlock(tdb, -1, F_WRLCK);		goto fail;	}	/* we have to allocate some space */	rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);	tdb_unlock(tdb, -1, F_WRLCK);	if (rec_ptr == 0) {		goto fail;	}	/* Read hash top into next ptr */	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)		goto fail;	rec.key_len = key.dsize;	rec.data_len = dbuf.dsize;	rec.full_hash = hash;	rec.magic = TDB_MAGIC;	/* write out and point the top of the hash chain at it */	if (tdb_rec_write(tdb, rec_ptr, &rec) == -1	    || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1	    || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {		/* Need to tdb_unallocate() here */		goto fail;	} done:	ret = 0; fail:	if (ret == 0) {		tdb_increment_seqnum(tdb);	}	SAFE_FREE(p); 	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);	return ret;}/* Append to an entry. Create if not exist. */int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf){	u32 hash;	TDB_DATA dbuf;	int ret = -1;	/* find which hash bucket it is in */	hash = tdb->hash_fn(&key);	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)		return -1;	dbuf = tdb_fetch(tdb, key);	if (dbuf.dptr == NULL) {		dbuf.dptr = (char *)malloc(new_dbuf.dsize);	} else {		dbuf.dptr = (char *)realloc(dbuf.dptr,					    dbuf.dsize + new_dbuf.dsize);	}	if (dbuf.dptr == NULL) {		tdb->ecode = TDB_ERR_OOM;		goto failed;	}	memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);	dbuf.dsize += new_dbuf.dsize;	ret = tdb_store(tdb, key, dbuf, 0);	failed:	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);	SAFE_FREE(dbuf.dptr);	return ret;}/*  return the name of the current tdb file  useful for external logging functions*/const char *tdb_name(struct tdb_context *tdb){	return tdb->name;}/*  return the underlying file descriptor being used by tdb, or -1  useful for external routines that want to check the device/inode  of the fd*/int tdb_fd(struct tdb_context *tdb){	return tdb->fd;}/*  return the current logging function  useful for external tdb routines that wish to log tdb errors*/tdb_log_func tdb_log_fn(struct tdb_context *tdb){	return tdb->log.log_fn;}/*  get the tdb sequence number. Only makes sense if the writers opened  with TDB_SEQNUM set. Note that this sequence number will wrap quite  quickly, so it should only be used for a 'has something changed'  test, not for code that relies on the count of the number of changes  made. If you want a counter then use a tdb record.  The aim of this sequence number is to allow for a very lightweight  test of a possible tdb change.*/int tdb_get_seqnum(struct tdb_context *tdb){	tdb_off_t seqnum=0;	tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);	return seqnum;}int tdb_hash_size(struct tdb_context *tdb){	return tdb->header.hash_size;}size_t tdb_map_size(struct tdb_context *tdb){	return tdb->map_size;}int tdb_get_flags(struct tdb_context *tdb){	return tdb->flags;}

⌨️ 快捷键说明

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