示例#1
0
文件: freelistcheck.c 项目: hef/samba
_PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
{
    struct tdb_context *mem_tdb = NULL;
    struct tdb_record rec;
    tdb_off_t rec_ptr, last_ptr;
    int ret = -1;

    *pnum_entries = 0;

    mem_tdb = tdb_open("flval", tdb->hash_size,
                       TDB_INTERNAL, O_RDWR, 0600);
    if (!mem_tdb) {
        return -1;
    }

    if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
        tdb_close(mem_tdb);
        return 0;
    }

    last_ptr = FREELIST_TOP;

    /* Store the FREELIST_TOP record. */
    if (seen_insert(mem_tdb, last_ptr) == -1) {
        tdb->ecode = TDB_ERR_CORRUPT;
        ret = -1;
        goto fail;
    }

    /* read in the freelist top */
    if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) {
        goto fail;
    }

    while (rec_ptr) {

        /* If we can't store this record (we've seen it
           before) then the free list has a loop and must
           be corrupt. */

        if (seen_insert(mem_tdb, rec_ptr)) {
            tdb->ecode = TDB_ERR_CORRUPT;
            ret = -1;
            goto fail;
        }

        if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
            goto fail;
        }

        /* move to the next record */
        last_ptr = rec_ptr;
        rec_ptr = rec.next;
        *pnum_entries += 1;
    }

    ret = 0;

fail:

    tdb_close(mem_tdb);
    tdb_unlock(tdb, -1, F_WRLCK);
    return ret;
}
示例#2
0
文件: freelist.c 项目: csesteban/ccan
/* allocate some space from the free list. The offset returned points
   to a unconnected tdb_record within the database with room for at
   least length bytes of total data

   0 is returned if the space could not be allocated
 */
tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
{
	tdb_off_t rec_ptr, last_ptr, newrec_ptr;
	struct {
		tdb_off_t rec_ptr, last_ptr;
		tdb_len_t rec_len;
	} bestfit;
	float multiplier = 1.0;

	if (tdb_lock(tdb, -1, F_WRLCK) == -1)
		return 0;

	/* over-allocate to reduce fragmentation */
	length *= 1.25;

	/* Extra bytes required for tailer */
	length += sizeof(tdb_off_t);
	length = TDB_ALIGN(length, TDB_ALIGNMENT);

 again:
	last_ptr = FREELIST_TOP;

	/* read in the freelist top */
	if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
		goto fail;

	bestfit.rec_ptr = 0;
	bestfit.last_ptr = 0;
	bestfit.rec_len = 0;

	/* 
	   this is a best fit allocation strategy. Originally we used
	   a first fit strategy, but it suffered from massive fragmentation
	   issues when faced with a slowly increasing record size.
	 */
	while (rec_ptr) {
		if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
			goto fail;
		}

		if (rec->rec_len >= length) {
			if (bestfit.rec_ptr == 0 ||
			    rec->rec_len < bestfit.rec_len) {
				bestfit.rec_len = rec->rec_len;
				bestfit.rec_ptr = rec_ptr;
				bestfit.last_ptr = last_ptr;
			}
		}

		/* move to the next record */
		last_ptr = rec_ptr;
		rec_ptr = rec->next;

		/* if we've found a record that is big enough, then
		   stop searching if its also not too big. The
		   definition of 'too big' changes as we scan
		   through */
		if (bestfit.rec_len > 0 &&
		    bestfit.rec_len < length * multiplier) {
			break;
		}
		
		/* this multiplier means we only extremely rarely
		   search more than 50 or so records. At 50 records we
		   accept records up to 11 times larger than what we
		   want */
		multiplier *= 1.05;
	}

	if (bestfit.rec_ptr != 0) {
		if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
			goto fail;
		}

		newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, 
					      rec, bestfit.last_ptr);
		tdb_unlock(tdb, -1, F_WRLCK);
		return newrec_ptr;
	}

	/* 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;
}