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

📄 tdb.c

📁 自己精简过的PPPD代码。在嵌入中应用可以更好的发挥。比原先的小了很多
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct list_struct rec;	tdb_off tailer_ofs, tailer;	if (tdb_read(tdb, offset, (char *)&rec, sizeof(rec), DOCONV()) == -1) {		printf("ERROR: failed to read record at %u\n", offset);		return 0;	}	printf(" rec: offset=%u next=%d rec_len=%d key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",	       offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, rec.full_hash, rec.magic);	tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off);	if (ofs_read(tdb, tailer_ofs, &tailer) == -1) {		printf("ERROR: failed to read tailer at %u\n", tailer_ofs);		return rec.next;	}	if (tailer != rec.rec_len + sizeof(rec)) {		printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",				(unsigned)tailer, (unsigned)(rec.rec_len + sizeof(rec)));	}	return rec.next;}static int tdb_dump_chain(TDB_CONTEXT *tdb, int i){	tdb_off rec_ptr, top;	top = TDB_HASH_TOP(i);	if (tdb_lock(tdb, i, F_WRLCK) != 0)		return -1;	if (ofs_read(tdb, top, &rec_ptr) == -1)		return tdb_unlock(tdb, i, F_WRLCK);	if (rec_ptr)		printf("hash=%d\n", i);	while (rec_ptr) {		rec_ptr = tdb_dump_record(tdb, rec_ptr);	}	return tdb_unlock(tdb, i, F_WRLCK);}void tdb_dump_all(TDB_CONTEXT *tdb){	int i;	for (i=0;i<tdb->header.hash_size;i++) {		tdb_dump_chain(tdb, i);	}	printf("freelist:\n");	tdb_dump_chain(tdb, -1);}int tdb_printfreelist(TDB_CONTEXT *tdb){	int ret;	long total_free = 0;	tdb_off offset, rec_ptr;	struct list_struct rec;	if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)		return ret;	offset = FREELIST_TOP;	/* read in the freelist top */	if (ofs_read(tdb, offset, &rec_ptr) == -1) {		tdb_unlock(tdb, -1, F_WRLCK);		return 0;	}	printf("freelist top=[0x%08x]\n", rec_ptr );	while (rec_ptr) {		if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec), DOCONV()) == -1) {			tdb_unlock(tdb, -1, F_WRLCK);			return -1;		}		if (rec.magic != TDB_FREE_MAGIC) {			printf("bad magic 0x%08x in free list\n", rec.magic);			tdb_unlock(tdb, -1, F_WRLCK);			return -1;		}		printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)]\n", rec.next, rec.rec_len, rec.rec_len );		total_free += rec.rec_len;		/* move to the next record */		rec_ptr = rec.next;	}	printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,                (int)total_free);	return tdb_unlock(tdb, -1, F_WRLCK);}/* Remove an element from the freelist.  Must have alloc lock. */static int remove_from_freelist(TDB_CONTEXT *tdb, tdb_off off, tdb_off next){	tdb_off last_ptr, i;	/* read in the freelist top */	last_ptr = FREELIST_TOP;	while (ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {		if (i == off) {			/* We've found it! */			return ofs_write(tdb, last_ptr, &next);		}		/* Follow chain (next offset is at start of record) */		last_ptr = i;	}	TDB_LOG((tdb, 0,"remove_from_freelist: not on list at off=%d\n", off));	return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);}/* Add an element into the freelist. Merge adjacent records if   neccessary. */static int tdb_free(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec){	tdb_off right, left;	/* Allocation and tailer lock */	if (tdb_lock(tdb, -1, F_WRLCK) != 0)		return -1;	/* set an initial tailer, so if we fail we don't leave a bogus record */	if (update_tailer(tdb, offset, rec) != 0) {		TDB_LOG((tdb, 0, "tdb_free: upfate_tailer failed!\n"));		goto fail;	}	/* Look right first (I'm an Australian, dammit) */	right = offset + sizeof(*rec) + rec->rec_len;	if (right + sizeof(*rec) <= tdb->map_size) {		struct list_struct r;		if (tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {			TDB_LOG((tdb, 0, "tdb_free: right read failed at %u\n", right));			goto left;		}		/* If it's free, expand to include it. */		if (r.magic == TDB_FREE_MAGIC) {			if (remove_from_freelist(tdb, right, r.next) == -1) {				TDB_LOG((tdb, 0, "tdb_free: right free failed at %u\n", right));				goto left;			}			rec->rec_len += sizeof(r) + r.rec_len;		}	}left:	/* Look left */	left = offset - sizeof(tdb_off);	if (left > TDB_DATA_START(tdb->header.hash_size)) {		struct list_struct l;		tdb_off leftsize;				/* Read in tailer and jump back to header */		if (ofs_read(tdb, left, &leftsize) == -1) {			TDB_LOG((tdb, 0, "tdb_free: left offset read failed at %u\n", left));			goto update;		}		left = offset - leftsize;		/* Now read in record */		if (tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {			TDB_LOG((tdb, 0, "tdb_free: left read failed at %u (%u)\n", left, leftsize));			goto update;		}		/* If it's free, expand to include it. */		if (l.magic == TDB_FREE_MAGIC) {			if (remove_from_freelist(tdb, left, l.next) == -1) {				TDB_LOG((tdb, 0, "tdb_free: left free failed at %u\n", left));				goto update;			} else {				offset = left;				rec->rec_len += leftsize;			}		}	}update:	if (update_tailer(tdb, offset, rec) == -1) {		TDB_LOG((tdb, 0, "tdb_free: update_tailer failed at %u\n", offset));		goto fail;	}	/* Now, prepend to free list */	rec->magic = TDB_FREE_MAGIC;	if (ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||	    rec_write(tdb, offset, rec) == -1 ||	    ofs_write(tdb, FREELIST_TOP, &offset) == -1) {		TDB_LOG((tdb, 0, "tdb_free record write failed at offset=%d\n", offset));		goto fail;	}	/* And we're done. */	tdb_unlock(tdb, -1, F_WRLCK);	return 0; fail:	tdb_unlock(tdb, -1, F_WRLCK);	return -1;}/* expand a file.  we prefer to use ftruncate, as that is what posix  says to use for mmap expansion */static int expand_file(TDB_CONTEXT *tdb, tdb_off size, tdb_off addition){	char buf[1024];#if HAVE_FTRUNCATE_EXTEND	if (ftruncate(tdb->fd, size+addition) != 0) {		TDB_LOG((tdb, 0, "expand_file ftruncate to %d failed (%s)\n", 			   size+addition, strerror(errno)));		return -1;	}#else	char b = 0;#ifdef HAVE_PWRITE	if (pwrite(tdb->fd,  &b, 1, (size+addition) - 1) != 1) {#else	if (lseek(tdb->fd, (size+addition) - 1, SEEK_SET) != (size+addition) - 1 || 	    write(tdb->fd, &b, 1) != 1) {#endif		TDB_LOG((tdb, 0, "expand_file to %d failed (%s)\n", 			   size+addition, strerror(errno)));		return -1;	}#endif	/* now fill the file with something. This ensures that the file isn't sparse, which would be	   very bad if we ran out of disk. This must be done with write, not via mmap */	memset(buf, 0x42, sizeof(buf));	while (addition) {		int n = addition>sizeof(buf)?sizeof(buf):addition;#ifdef HAVE_PWRITE		int ret = pwrite(tdb->fd, buf, n, size);#else		int ret;		if (lseek(tdb->fd, size, SEEK_SET) != size)			return -1;		ret = write(tdb->fd, buf, n);#endif		if (ret != n) {			TDB_LOG((tdb, 0, "expand_file write of %d failed (%s)\n", 				   n, strerror(errno)));			return -1;		}		addition -= n;		size += n;	}	return 0;}/* expand the database at least size bytes by expanding the underlying   file and doing the mmap again if necessary */static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size){	struct list_struct rec;	tdb_off offset;	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {		TDB_LOG((tdb, 0, "lock failed in tdb_expand\n"));		return -1;	}	/* must know about any previous expansions by another process */	tdb_oob(tdb, tdb->map_size + 1, 1);	/* always make room for at least 10 more records, and round           the database up to a multiple of TDB_PAGE_SIZE */	size = TDB_ALIGN(tdb->map_size + size*10, TDB_PAGE_SIZE) - tdb->map_size;	if (!(tdb->flags & TDB_INTERNAL))		tdb_munmap(tdb);	/*	 * We must ensure the file is unmapped before doing this	 * to ensure consistency with systems like OpenBSD where	 * writes and mmaps are not consistent.	 */	/* expand the file itself */	if (!(tdb->flags & TDB_INTERNAL)) {		if (expand_file(tdb, tdb->map_size, size) != 0)			goto fail;	}	tdb->map_size += size;	if (tdb->flags & TDB_INTERNAL)		tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size);	else {		/*		 * We must ensure the file is remapped before adding the space		 * to ensure consistency with systems like OpenBSD where		 * writes and mmaps are not consistent.		 */		/* We're ok if the mmap fails as we'll fallback to read/write */		tdb_mmap(tdb);	}	/* form a new freelist record */	memset(&rec,'\0',sizeof(rec));	rec.rec_len = size - sizeof(rec);	/* link it into the free list */	offset = tdb->map_size - size;	if (tdb_free(tdb, offset, &rec) == -1)		goto fail;	tdb_unlock(tdb, -1, F_WRLCK);	return 0; fail:	tdb_unlock(tdb, -1, F_WRLCK);	return -1;}/* allocate some space from the free list. The offset returned points   to a unconnected list_struct within the database with room for at   least length bytes of total data   0 is returned if the space could not be allocated */static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length,			    struct list_struct *rec){	tdb_off rec_ptr, last_ptr, newrec_ptr;	struct list_struct newrec;	memset(&newrec, '\0', sizeof(newrec));	if (tdb_lock(tdb, -1, F_WRLCK) == -1)		return 0;	/* Extra bytes required for tailer */	length += sizeof(tdb_off); again:	last_ptr = FREELIST_TOP;	/* read in the freelist top */	if (ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)		goto fail;	/* keep looking until we find a freelist record big enough */	while (rec_ptr) {		if (rec_free_read(tdb, rec_ptr, rec) == -1)			goto fail;		if (rec->rec_len >= length) {			/* found it - now possibly split it up  */			if (rec->rec_len > length + MIN_REC_SIZE) {				/* Length of left piece */				length = TDB_ALIGN(length, TDB_ALIGNMENT);				/* Right piece to go on free list */				newrec.rec_len = rec->rec_len					- (sizeof(*rec) + length);				newrec_ptr = rec_ptr + sizeof(*rec) + length;				/* And left record is shortened */				rec->rec_len = length;			} else				newrec_ptr = 0;			/* Remove allocated record from the free list */			if (ofs_write(tdb, last_ptr, &rec->next) == -1)				goto fail;			/* Update header: do this before we drop alloc                           lock, otherwise tdb_free() might try to                           merge with us, thinking we're free.                           (Thanks Jeremy Allison). */			rec->magic = TDB_MAGIC;			if (rec_write(tdb, rec_ptr, rec) == -1)				goto fail;			/* Did we create new block? */			if (newrec_ptr) {				/* Update allocated record tailer (we                                   shortened it). */				if (update_tailer(tdb, rec_ptr, rec) == -1)					goto fail;				/* Free new record */				if (tdb_free(tdb, newrec_ptr, &newrec) == -1)					goto fail;			}			/* all done - return the new record offset */			tdb_unlock(tdb, -1, F_WRLCK);			return rec_ptr;		}		/* move to the next record */		last_ptr = rec_ptr;		rec_ptr = rec->next;	}	/* we didn't find enough space. See if we can expand the	   database and if we can then try again */	if (tdb_expand(tdb, length + sizeof(*rec)) == 0)		goto again; fail:	tdb_unlock(tdb, -1, F_WRLCK);	return 0;}/* initialise a new database with a specified hash size */static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size){	struct tdb_header *newdb;	int size, ret = -1;	/* We make it up in memory, then write it out if not internal */	size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off);	if (!(newdb = calloc(size, 1)))		return TDB_ERRCODE(TDB_ERR_OOM, -1);	/* Fill in the header */	newdb->version = TDB_VERSION;	newdb->hash_size = hash_size;	if (tdb->flags & TDB_INTERNAL) {		tdb->map_size = size;		tdb->map_ptr = (char *)newdb;		memcpy(&tdb->header, newdb, sizeof(tdb->header));		/* Convert the `ondisk' version if asked. */		CONVERT(*newdb);		return 0;	}	if (lseek(tdb->fd, 0, SEEK_SET) == -1)		goto fail;	if (ftruncate(tdb->fd, 0) == -1)		goto fail;	/* This creates an endian-converted header, as if read from disk */	CONVERT(*newdb);	memcpy(&tdb->header, newdb, sizeof(tdb->header));	/* Don't endian-convert the magic food! */	memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);	if (write(tdb->fd, newdb, size) != size)		ret = -1;	else		ret = tdb_create_rwlocks(tdb->fd, hash_size);  fail:	SAFE_FREE(newdb);	return ret;}/* Returns 0 on fail.  On success, return offset of record, and fills   in rec */static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash,			struct list_struct *r){	tdb_off rec_ptr;		/* read in the hash top */	if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)		return 0;	/* keep looking until we find the right record */	while (rec_ptr) {		if (rec_read(tdb, rec_ptr, r) == -1)			return 0;		if (!TDB_DEAD(r) && hash==r->full_hash && key.dsize==r->key_len) {			char *k;			/* a very likely hit - read the key */			k = tdb_alloc_read(tdb, rec_ptr + sizeof(*r), 					   r->key_len);			if (!k)				return 0;			if (memcmp(key.dptr, k, key.dsize) == 0) {				SAFE_FREE(k);				return rec_ptr;			}			SAFE_FREE(k);		}		rec_ptr = r->next;	}	return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);}/* As tdb_find, but if you succeed, keep the lock */static tdb_off tdb_find_lock_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash, int locktype,			     struct list_struct *rec){	u32 rec_ptr;	if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)		return 0;

⌨️ 快捷键说明

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