mirror of
https://github.com/MariaDB/server.git
synced 2025-01-22 14:54:20 +01:00
git-svn-id: file:///svn/tokudb.1131b+1080a@6076 c7de825b-a66e-492c-adef-691d508d4ae1
This commit is contained in:
parent
fcd8cb084c
commit
9e8e600430
11 changed files with 451 additions and 2 deletions
|
@ -56,6 +56,7 @@ build default: bins libs tdb-recover tdb_logprint $(TEST_OFILES)
|
||||||
cd tests;$(MAKE) build
|
cd tests;$(MAKE) build
|
||||||
|
|
||||||
BRT_SOURCES = \
|
BRT_SOURCES = \
|
||||||
|
block_allocator \
|
||||||
bread \
|
bread \
|
||||||
brt-serialize \
|
brt-serialize \
|
||||||
brt-verify \
|
brt-verify \
|
||||||
|
|
178
newbrt/block_allocator.c
Normal file
178
newbrt/block_allocator.c
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/* -*- mode: C; c-basic-offset: 4 -*- */
|
||||||
|
#include "block_allocator.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "toku_assert.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Here's a very simple implementation.
|
||||||
|
// It's not very fast at allocating or freeing.
|
||||||
|
|
||||||
|
|
||||||
|
struct blockpair {
|
||||||
|
u_int64_t offset;
|
||||||
|
u_int64_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct block_allocator {
|
||||||
|
u_int64_t reserve_at_beginning; // How much to reserve at the beginning
|
||||||
|
u_int64_t n_blocks; // How many blocks
|
||||||
|
u_int64_t blocks_array_size; // How big is the blocks_array. Must be >= n_blocks.
|
||||||
|
struct blockpair *blocks_array; // These blocks are sorted by address.
|
||||||
|
u_int64_t next_fit_counter; // Used for the next_fit algorithm.
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_validate (BLOCK_ALLOCATOR ba) {
|
||||||
|
u_int64_t i;
|
||||||
|
for (i=0; i<ba->n_blocks; i++) {
|
||||||
|
if (i>0) {
|
||||||
|
assert(ba->blocks_array[i].offset > ba->blocks_array[i-1].offset);
|
||||||
|
assert(ba->blocks_array[i].offset >= ba->blocks_array[i-1].offset + ba->blocks_array[i-1].size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
block_allocator_print (BLOCK_ALLOCATOR ba) {
|
||||||
|
u_int64_t i;
|
||||||
|
for (i=0; i<ba->n_blocks; i++) {
|
||||||
|
printf("%" PRId64 ":%" PRId64 " ", ba->blocks_array[i].offset, ba->blocks_array[i].size);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
create_block_allocator (BLOCK_ALLOCATOR *ba, u_int64_t reserve_at_beginning) {
|
||||||
|
BLOCK_ALLOCATOR XMALLOC(result);
|
||||||
|
result->reserve_at_beginning = reserve_at_beginning;
|
||||||
|
result->n_blocks = 0;
|
||||||
|
result->blocks_array_size = 1;
|
||||||
|
XMALLOC_N(result->blocks_array_size, result->blocks_array);
|
||||||
|
result->next_fit_counter = 0;
|
||||||
|
*ba = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
destroy_block_allocator (BLOCK_ALLOCATOR *bap) {
|
||||||
|
BLOCK_ALLOCATOR ba = *bap;
|
||||||
|
*bap = 0;
|
||||||
|
toku_free(ba->blocks_array);
|
||||||
|
toku_free(ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grow_blocks_array (BLOCK_ALLOCATOR ba) {
|
||||||
|
if (ba->n_blocks >= ba->blocks_array_size) {
|
||||||
|
ba->blocks_array_size *= 2;
|
||||||
|
XREALLOC_N(ba->blocks_array_size, ba->blocks_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_alloc_block_at (BLOCK_ALLOCATOR ba, u_int64_t size, u_int64_t offset) {
|
||||||
|
u_int64_t i;
|
||||||
|
grow_blocks_array(ba);
|
||||||
|
// Just do a linear search for the block
|
||||||
|
for (i=0; i<ba->n_blocks; i++) {
|
||||||
|
if (ba->blocks_array[i].offset > offset) {
|
||||||
|
// allocate it in that slot
|
||||||
|
// Don't do error checking, since we require that the blocks don't overlap.
|
||||||
|
// Slide everything over
|
||||||
|
memmove(ba->blocks_array+i, ba->blocks_array+i-1, (ba->n_blocks - i)*sizeof(struct blockpair));
|
||||||
|
ba->blocks_array[i].offset = offset;
|
||||||
|
ba->blocks_array[i].size = size;
|
||||||
|
ba->n_blocks++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Goes at the end
|
||||||
|
ba->blocks_array[ba->n_blocks].offset = offset;
|
||||||
|
ba->blocks_array[ba->n_blocks].size = size;
|
||||||
|
ba->n_blocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_alloc_block (BLOCK_ALLOCATOR ba, u_int64_t size, u_int64_t *offset) {
|
||||||
|
grow_blocks_array(ba);
|
||||||
|
if (ba->n_blocks==0) {
|
||||||
|
ba->blocks_array[0].offset = ba->reserve_at_beginning;
|
||||||
|
ba->blocks_array[0].size = size;
|
||||||
|
*offset = ba->reserve_at_beginning;
|
||||||
|
ba->n_blocks++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u_int64_t i;
|
||||||
|
u_int64_t blocknum = ba->next_fit_counter;
|
||||||
|
// Implement next fit.
|
||||||
|
for (i=0; i<ba->n_blocks; i++, blocknum++) {
|
||||||
|
if (blocknum>=ba->n_blocks) blocknum=0;
|
||||||
|
// Consider the space after blocknum
|
||||||
|
if (blocknum+1 ==ba->n_blocks) continue; // Can't use the space after the last block, since that would be new space.
|
||||||
|
struct blockpair *bp = &ba->blocks_array[blocknum];
|
||||||
|
u_int64_t this_offset = bp[0].offset;
|
||||||
|
u_int64_t this_size = bp[0].size;
|
||||||
|
u_int64_t answer_offset = this_offset + this_size;
|
||||||
|
if (answer_offset + size > bp[1].offset) continue; // The block we want doesn't fit after this block.
|
||||||
|
// It fits, so allocate it here.
|
||||||
|
memmove(bp+2, bp+1, (ba->n_blocks - blocknum -1)*sizeof(struct blockpair));
|
||||||
|
bp[1].offset = answer_offset;
|
||||||
|
bp[1].size = size;
|
||||||
|
ba->n_blocks++;
|
||||||
|
ba->next_fit_counter = blocknum;
|
||||||
|
*offset = answer_offset;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// It didn't fit anywhere, so fit it on the end.
|
||||||
|
struct blockpair *bp = &ba->blocks_array[ba->n_blocks];
|
||||||
|
u_int64_t answer_offset = bp[-1].offset+bp[-1].size;
|
||||||
|
bp->offset = answer_offset;
|
||||||
|
bp->size = size;
|
||||||
|
ba->n_blocks++;
|
||||||
|
*offset = answer_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
find_block (BLOCK_ALLOCATOR ba, u_int64_t offset)
|
||||||
|
// Find the index in the blocks array that has a particular offset. Requires that the block exist.
|
||||||
|
// Use binary search so it runs fast.
|
||||||
|
{
|
||||||
|
if (ba->n_blocks==1) {
|
||||||
|
assert(ba->blocks_array[0].offset == offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
u_int64_t lo = 0;
|
||||||
|
u_int64_t hi = ba->n_blocks;
|
||||||
|
while (1) {
|
||||||
|
assert(lo<hi); // otherwise no such block exists.
|
||||||
|
u_int64_t mid = (lo+hi)/2;
|
||||||
|
u_int64_t thisoff = ba->blocks_array[mid].offset;
|
||||||
|
//printf("lo=%" PRId64 " hi=%" PRId64 " mid=%" PRId64 " thisoff=%" PRId64 " offset=%" PRId64 "\n", lo, hi, mid, thisoff, offset);
|
||||||
|
if (thisoff < offset) {
|
||||||
|
lo = mid+1;
|
||||||
|
} else if (thisoff > offset) {
|
||||||
|
hi = mid;
|
||||||
|
} else {
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_free_block (BLOCK_ALLOCATOR ba, u_int64_t offset) {
|
||||||
|
int64_t bn = find_block(ba, offset);
|
||||||
|
assert(bn>=0); // we require that there is a block with that offset. Might as well abort if no such block exists.
|
||||||
|
memmove(&ba->blocks_array[bn], &ba->blocks_array[bn+1], (ba->n_blocks-bn-1) * sizeof(struct blockpair));
|
||||||
|
ba->n_blocks--;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int64_t
|
||||||
|
block_allocator_block_size (BLOCK_ALLOCATOR ba, u_int64_t offset) {
|
||||||
|
int64_t bn = find_block(ba, offset);
|
||||||
|
assert(bn>=0); // we require that there is a block with that offset. Might as well abort if no such block exists.
|
||||||
|
return ba->blocks_array[bn].size;
|
||||||
|
}
|
87
newbrt/block_allocator.h
Normal file
87
newbrt/block_allocator.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/* -*- mode: C; c-basic-offset: 4 -*- */
|
||||||
|
#ifndef BLOCK_ALLOCATOR_H
|
||||||
|
#define BLOCK_ALLOCATOR_H
|
||||||
|
|
||||||
|
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
||||||
|
|
||||||
|
#include "brttypes.h"
|
||||||
|
|
||||||
|
// A block allocator manages the allocation of variable-sized blocks.
|
||||||
|
// The translation of block numbers to addresses is handled elsewhere.
|
||||||
|
// The allocation of block numbers is handled elsewhere.
|
||||||
|
|
||||||
|
// We can create a block allocator.
|
||||||
|
// When creating a block allocator we also specify a certain-sized
|
||||||
|
// block at the beginning that is preallocated (and cannot be allocated
|
||||||
|
// or freed)
|
||||||
|
|
||||||
|
// We can allocate blocks of a particular size at a particular location.
|
||||||
|
// We can allocate blocks of a particular size at a location chosen by the allocator.
|
||||||
|
// We can free blocks.
|
||||||
|
// We can determine the size of a block.
|
||||||
|
|
||||||
|
typedef struct block_allocator *BLOCK_ALLOCATOR;
|
||||||
|
|
||||||
|
void
|
||||||
|
create_block_allocator (BLOCK_ALLOCATOR * ba, u_int64_t reserve_at_beginning);
|
||||||
|
// Effect: Create a block allocator, in which the first RESERVE_AT_BEGINNING bytes are not put into a block.
|
||||||
|
// Aborts if we run out of memory.
|
||||||
|
// Parameters
|
||||||
|
// ba (OUT): Result stored here.
|
||||||
|
// reserve_at_beginning (IN) Size of reserved block at beginning.
|
||||||
|
|
||||||
|
void
|
||||||
|
destroy_block_allocator (BLOCK_ALLOCATOR *ba);
|
||||||
|
// Effect: Destroy a block allocator at *ba.
|
||||||
|
// Also, set *ba=NULL.
|
||||||
|
// Rationale: If there was only one copy of the pointer, this kills that copy too.
|
||||||
|
// Paramaters:
|
||||||
|
// ba (IN/OUT):
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_alloc_block_at (BLOCK_ALLOCATOR ba, u_int64_t size, u_int64_t offset);
|
||||||
|
// Effect: Allocate a block of the specified size at a particular offset.
|
||||||
|
// Aborts if anything goes wrong.
|
||||||
|
// Requires: The resulting block may not overlap any other allocated block.
|
||||||
|
// Parameters:
|
||||||
|
// ba (IN/OUT): The block allocator. (Modifies ba.)
|
||||||
|
// size (IN): The size of the block.
|
||||||
|
// offset (IN): The location of the block.
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_alloc_block (BLOCK_ALLOCATOR ba, u_int64_t size, u_int64_t *offset);
|
||||||
|
// Effect: Allocate a block of the specified size at an address chosen by the allocator.
|
||||||
|
// Aborts if anything goes wrong.
|
||||||
|
// Parameters:
|
||||||
|
// ba (IN/OUT): The block allocator. (Modifies ba.)
|
||||||
|
// size (IN): The size of the block.
|
||||||
|
// offset (OUT): The location of the block.
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_free_block (BLOCK_ALLOCATOR ba, u_int64_t offset);
|
||||||
|
// Effect: Free the block at offset.
|
||||||
|
// Requires: There must be a block currently allocated at that offset.
|
||||||
|
// Parameters:
|
||||||
|
// ba (IN/OUT): The block allocator. (Modifies ba.)
|
||||||
|
// offset (IN): The offset of the block.
|
||||||
|
|
||||||
|
|
||||||
|
u_int64_t
|
||||||
|
block_allocator_block_size (BLOCK_ALLOCATOR ba, u_int64_t offset);
|
||||||
|
// Effect: Return the size of the block that starts at offset.
|
||||||
|
// Requires: There must be a block currently allocated at that offset.
|
||||||
|
// Parameters:
|
||||||
|
// ba (IN/OUT): The block allocator. (Modifies ba.)
|
||||||
|
// offset (IN): The offset of the block.
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_validate (BLOCK_ALLOCATOR ba);
|
||||||
|
// Effect: Check to see if the block allocator is OK. This may take a long time.
|
||||||
|
// Usage Hints: Probably only use this for unit tests.
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_print (BLOCK_ALLOCATOR ba);
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,6 +4,7 @@
|
||||||
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
||||||
|
|
||||||
#include "toku_assert.h"
|
#include "toku_assert.h"
|
||||||
|
#include "block_allocator.h"
|
||||||
#include "cachetable.h"
|
#include "cachetable.h"
|
||||||
#include "fifo.h"
|
#include "fifo.h"
|
||||||
#include "brt.h"
|
#include "brt.h"
|
||||||
|
@ -131,6 +132,14 @@ struct brt_header {
|
||||||
//struct block_descriptor *blocks;
|
//struct block_descriptor *blocks;
|
||||||
BLOCKNUM free_blocks; // free list for blocks. Use -1 to indicate that there are no free blocks
|
BLOCKNUM free_blocks; // free list for blocks. Use -1 to indicate that there are no free blocks
|
||||||
BLOCKNUM unused_blocks; // first unused block
|
BLOCKNUM unused_blocks; // first unused block
|
||||||
|
|
||||||
|
// Where and how big is the block allocation vector?
|
||||||
|
// The block allocation vector translates block numbers to offsets (DISKOFF) in the file.
|
||||||
|
// We use a DISKOFF for the vector location, because we cannot use block numbers to bootstrap the indirection table.
|
||||||
|
BLOCKNUM block_allocation_vector_length; // It's a blocknum because the block allocation vector is indexed by blocknums.
|
||||||
|
DISKOFF block_allocation_vector_location; // Remember this so we can free the block before writing a new one.
|
||||||
|
// The in-memory data structure for block allocation
|
||||||
|
BLOCK_ALLOCATOR block_allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct brt {
|
struct brt {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
||||||
|
|
||||||
#include "toku_assert.h"
|
#include "toku_assert.h"
|
||||||
|
#include "block_allocator.h"
|
||||||
#include "brt-internal.h"
|
#include "brt-internal.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "rbuf.h"
|
#include "rbuf.h"
|
||||||
|
@ -15,6 +16,16 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
static u_int64_t ntohll(u_int64_t v) {
|
||||||
|
union u {
|
||||||
|
u_int32_t l[2];
|
||||||
|
u_int64_t ll;
|
||||||
|
} uv;
|
||||||
|
uv.ll = v;
|
||||||
|
return (((u_int64_t)uv.l[0])<<32) + uv.l[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Don't include the compressed data size or the uncompressed data size.
|
// Don't include the compressed data size or the uncompressed data size.
|
||||||
|
|
||||||
static const int brtnode_header_overhead = (8+ // magic "tokunode" or "tokuleaf"
|
static const int brtnode_header_overhead = (8+ // magic "tokunode" or "tokuleaf"
|
||||||
|
@ -575,6 +586,18 @@ int toku_serialize_brt_header_to_wbuf (struct wbuf *wbuf, struct brt_header *h)
|
||||||
wbuf_BLOCKNUM(wbuf, h->free_blocks);
|
wbuf_BLOCKNUM(wbuf, h->free_blocks);
|
||||||
wbuf_BLOCKNUM(wbuf, h->unused_blocks);
|
wbuf_BLOCKNUM(wbuf, h->unused_blocks);
|
||||||
wbuf_int (wbuf, h->n_named_roots);
|
wbuf_int (wbuf, h->n_named_roots);
|
||||||
|
if (h->block_allocation_vector_length.b != 0) {
|
||||||
|
block_allocator_free_block(h->block_allocator, h->block_allocation_vector_location);
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
h->block_allocation_vector_length.b = block_allocator_get_vector_length(h->block_allocator);
|
||||||
|
{
|
||||||
|
int r = block_allocator_alloc_block(h->block_allocator, 0, h->block_allocation_vector_length.b, (u_int64_t*)&h->block_allocation_vector_location);
|
||||||
|
assert(r==0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
wbuf_BLOCKNUM(wbuf, h->block_allocation_vector_length);
|
||||||
|
wbuf_DISKOFF(wbuf, h->block_allocation_vector_location);
|
||||||
if (h->n_named_roots>=0) {
|
if (h->n_named_roots>=0) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<h->n_named_roots; i++) {
|
for (i=0; i<h->n_named_roots; i++) {
|
||||||
|
@ -632,6 +655,29 @@ int deserialize_brtheader (u_int32_t size, int fd, DISKOFF off, struct brt_heade
|
||||||
h->free_blocks = rbuf_blocknum(&rc);
|
h->free_blocks = rbuf_blocknum(&rc);
|
||||||
h->unused_blocks = rbuf_blocknum(&rc);
|
h->unused_blocks = rbuf_blocknum(&rc);
|
||||||
h->n_named_roots = rbuf_int(&rc);
|
h->n_named_roots = rbuf_int(&rc);
|
||||||
|
h->block_allocation_vector_length = rbuf_blocknum(&rc);
|
||||||
|
h->block_allocation_vector_location = rbuf_diskoff(&rc);
|
||||||
|
{
|
||||||
|
u_int64_t *block_locations_and_lengths = 0;
|
||||||
|
if (h->block_allocation_vector_length.b > 0) {
|
||||||
|
MALLOC_N(h->block_allocation_vector_length.b * 2, block_locations_and_lengths);
|
||||||
|
assert(block_locations_and_lengths);
|
||||||
|
u_int64_t len = h->block_allocation_vector_length.b * 16 + 4;
|
||||||
|
ssize_t r = pread(fd, block_locations_and_lengths, len, h->block_allocation_vector_location);
|
||||||
|
assert(r==(ssize_t)len);
|
||||||
|
u_int32_t x1764 = x1764_memory(block_locations_and_lengths, len-4); // compute a checksum
|
||||||
|
assert(x1764 == *(u_int32_t*)(block_locations_and_lengths+h->block_allocation_vector_length.b*2));
|
||||||
|
int i;
|
||||||
|
for (i=0; i<h->block_allocation_vector_length.b * 2; i++) {
|
||||||
|
block_locations_and_lengths[i] = ntohll(block_locations_and_lengths[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
int r = create_block_allocator(&h->block_allocator, h->block_allocation_vector_length.b, block_locations_and_lengths, h->nodesize);
|
||||||
|
assert(r==0);
|
||||||
|
#endif
|
||||||
|
if (block_locations_and_lengths) free(block_locations_and_lengths);
|
||||||
|
}
|
||||||
if (h->n_named_roots>=0) {
|
if (h->n_named_roots>=0) {
|
||||||
int i;
|
int i;
|
||||||
int n_to_malloc = (h->n_named_roots == 0) ? 1 : h->n_named_roots;
|
int n_to_malloc = (h->n_named_roots == 0) ? 1 : h->n_named_roots;
|
||||||
|
|
|
@ -20,7 +20,7 @@ typedef unsigned int ITEMLEN;
|
||||||
typedef const void *bytevec;
|
typedef const void *bytevec;
|
||||||
//typedef const void *bytevec;
|
//typedef const void *bytevec;
|
||||||
|
|
||||||
typedef long long DISKOFF; /* Offset in a disk. -1 is the NULL pointer. */
|
typedef int64_t DISKOFF; /* Offset in a disk. -1 is the NULL pointer. */
|
||||||
typedef u_int64_t TXNID;
|
typedef u_int64_t TXNID;
|
||||||
typedef struct s_blocknum { int64_t b; } BLOCKNUM; // make a struct so that we will notice type problems.
|
typedef struct s_blocknum { int64_t b; } BLOCKNUM; // make a struct so that we will notice type problems.
|
||||||
|
|
||||||
|
|
|
@ -741,7 +741,7 @@ int toku_logprint_DISKOFF (FILE *outf, FILE *inf, const char *fieldname, struct
|
||||||
DISKOFF v;
|
DISKOFF v;
|
||||||
int r = toku_fread_DISKOFF(inf, &v, checksum, len);
|
int r = toku_fread_DISKOFF(inf, &v, checksum, len);
|
||||||
if (r!=0) return r;
|
if (r!=0) return r;
|
||||||
fprintf(outf, " %s=%lld", fieldname, v);
|
fprintf(outf, " %s=%" PRId64, fieldname, v);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int toku_logprint_BLOCKNUM (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *checksum, u_int32_t *len, const char *format __attribute__((__unused__))) {
|
int toku_logprint_BLOCKNUM (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *checksum, u_int32_t *len, const char *format __attribute__((__unused__))) {
|
||||||
|
|
|
@ -18,6 +18,12 @@ void *toku_malloc(size_t size) {
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *toku_xmalloc(size_t size) {
|
||||||
|
void *r = malloc(size);
|
||||||
|
if (r==0) abort();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void *toku_tagmalloc(size_t size, enum typ_tag typtag) {
|
void *toku_tagmalloc(size_t size, enum typ_tag typtag) {
|
||||||
//printf("%s:%d tagmalloc\n", __FILE__, __LINE__);
|
//printf("%s:%d tagmalloc\n", __FILE__, __LINE__);
|
||||||
void *r = toku_malloc(size);
|
void *r = toku_malloc(size);
|
||||||
|
|
|
@ -22,6 +22,10 @@ enum typ_tag { TYP_BRTNODE = 0xdead0001,
|
||||||
/* Everything should call toku_malloc() instead of malloc(), and toku_calloc() instead of calloc() */
|
/* Everything should call toku_malloc() instead of malloc(), and toku_calloc() instead of calloc() */
|
||||||
void *toku_calloc(size_t nmemb, size_t size);
|
void *toku_calloc(size_t nmemb, size_t size);
|
||||||
void *toku_malloc(size_t size);
|
void *toku_malloc(size_t size);
|
||||||
|
|
||||||
|
// xmalloc aborts instead of return NULL if we run out of memory
|
||||||
|
void *toku_xmalloc(size_t size);
|
||||||
|
|
||||||
/* toku_tagmalloc() performs a malloc(size), but fills in the first 4 bytes with typ.
|
/* toku_tagmalloc() performs a malloc(size), but fills in the first 4 bytes with typ.
|
||||||
* This "tag" is useful if you are debugging and run across a void* that is
|
* This "tag" is useful if you are debugging and run across a void* that is
|
||||||
* really a (struct foo *), and you want to figure out what it is.
|
* really a (struct foo *), and you want to figure out what it is.
|
||||||
|
@ -53,6 +57,11 @@ void *toku_realloc(void *, size_t size);
|
||||||
|
|
||||||
#define REALLOC_N(n,v) v = toku_realloc(v, (n)*sizeof(*v))
|
#define REALLOC_N(n,v) v = toku_realloc(v, (n)*sizeof(*v))
|
||||||
|
|
||||||
|
// XMALLOC macros are like MALLOC except they abort if the operatoin fails
|
||||||
|
#define XMALLOC(v) v = toku_xmalloc(sizeof(*v))
|
||||||
|
#define XMALLOC_N(n,v) v = toku_malloc((n)*sizeof(*v))
|
||||||
|
#define XREALLOC_N(n,v) v = toku_realloc(v, (n)*sizeof(*v))
|
||||||
|
|
||||||
/* If you have a type such as
|
/* If you have a type such as
|
||||||
* struct pma *PMA;
|
* struct pma *PMA;
|
||||||
* and you define a corresponding int constant, such as
|
* and you define a corresponding int constant, such as
|
||||||
|
|
|
@ -49,6 +49,7 @@ endif
|
||||||
# Put these one-per-line so that if we insert a new one the svn diff can understand it better.
|
# Put these one-per-line so that if we insert a new one the svn diff can understand it better.
|
||||||
# Also keep them sorted.
|
# Also keep them sorted.
|
||||||
REGRESSION_TESTS = \
|
REGRESSION_TESTS = \
|
||||||
|
block_allocator_test \
|
||||||
bread-test \
|
bread-test \
|
||||||
brt-serialize-test \
|
brt-serialize-test \
|
||||||
brt-test \
|
brt-test \
|
||||||
|
|
112
newbrt/tests/block_allocator_test.c
Normal file
112
newbrt/tests/block_allocator_test.c
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/* -*- mode: C; c-basic-offset: 4 -*- */
|
||||||
|
#include "block_allocator.h"
|
||||||
|
#include "toku_assert.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static void ba_alloc_at (BLOCK_ALLOCATOR ba, u_int64_t size, u_int64_t offset) {
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
block_allocator_alloc_block_at(ba, size, offset);
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ba_alloc (BLOCK_ALLOCATOR ba, u_int64_t size, u_int64_t *answer) {
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
block_allocator_alloc_block(ba, size, answer);
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ba_free (BLOCK_ALLOCATOR ba, u_int64_t offset) {
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
block_allocator_free_block(ba, offset);
|
||||||
|
block_allocator_validate(ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple block allocator test
|
||||||
|
static void
|
||||||
|
test_ba0 (void) {
|
||||||
|
BLOCK_ALLOCATOR ba;
|
||||||
|
u_int64_t b0, b1;
|
||||||
|
create_block_allocator(&ba, 100);
|
||||||
|
ba_alloc_at(ba, 50, 100);
|
||||||
|
ba_alloc_at(ba, 25, 150);
|
||||||
|
ba_alloc (ba, 10, &b0);
|
||||||
|
assert(b0==175);
|
||||||
|
ba_free(ba, 150);
|
||||||
|
ba_alloc_at(ba, 10, 150);
|
||||||
|
ba_alloc(ba, 10, &b0);
|
||||||
|
assert(b0==160);
|
||||||
|
ba_alloc(ba, 10, &b0);
|
||||||
|
ba_alloc(ba, 113, &b1);
|
||||||
|
assert(113==block_allocator_block_size(ba, b1));
|
||||||
|
assert(10==block_allocator_block_size(ba, b0));
|
||||||
|
assert(50==block_allocator_block_size(ba, 100));
|
||||||
|
|
||||||
|
u_int64_t b2, b3, b4, b5, b6, b7;
|
||||||
|
ba_alloc(ba, 100, &b2);
|
||||||
|
ba_alloc(ba, 100, &b3);
|
||||||
|
ba_alloc(ba, 100, &b4);
|
||||||
|
ba_alloc(ba, 100, &b5);
|
||||||
|
ba_alloc(ba, 100, &b6);
|
||||||
|
ba_alloc(ba, 100, &b7);
|
||||||
|
ba_free(ba, b2);
|
||||||
|
ba_alloc(ba, 100, &b2);
|
||||||
|
ba_free(ba, b4);
|
||||||
|
ba_free(ba, b6);
|
||||||
|
u_int64_t b8, b9;
|
||||||
|
ba_alloc(ba, 100, &b4);
|
||||||
|
ba_free(ba, b2);
|
||||||
|
ba_alloc(ba, 100, &b6);
|
||||||
|
ba_alloc(ba, 100, &b8);
|
||||||
|
ba_alloc(ba, 100, &b9);
|
||||||
|
ba_free(ba, b6);
|
||||||
|
ba_free(ba, b7);
|
||||||
|
ba_free(ba, b8);
|
||||||
|
ba_alloc(ba, 100, &b6);
|
||||||
|
ba_alloc(ba, 100, &b7);
|
||||||
|
ba_free(ba, b4);
|
||||||
|
ba_alloc(ba, 100, &b4);
|
||||||
|
|
||||||
|
destroy_block_allocator(&ba);
|
||||||
|
assert(ba==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually to get coverage of all the code in the block allocator.
|
||||||
|
static void
|
||||||
|
test_ba1 (int n_initial) {
|
||||||
|
BLOCK_ALLOCATOR ba;
|
||||||
|
create_block_allocator(&ba, 0);
|
||||||
|
int i;
|
||||||
|
int n_blocks=0;
|
||||||
|
u_int64_t blocks[1000];
|
||||||
|
for (i=0; i<1000; i++) {
|
||||||
|
if (i<n_initial || random()%2 == 0) {
|
||||||
|
if (n_blocks<1000) {
|
||||||
|
ba_alloc(ba, 1, &blocks[n_blocks]);
|
||||||
|
//printf("A[%d]=%ld\n", n_blocks, blocks[n_blocks]);
|
||||||
|
n_blocks++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (n_blocks>0) {
|
||||||
|
int blocknum = random()%n_blocks;
|
||||||
|
//printf("F[%d]%ld\n", blocknum, blocks[blocknum]);
|
||||||
|
ba_free(ba, blocks[blocknum]);
|
||||||
|
blocks[blocknum]=blocks[n_blocks-1];
|
||||||
|
n_blocks--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_block_allocator(&ba);
|
||||||
|
assert(ba==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__))) {
|
||||||
|
test_ba0();
|
||||||
|
test_ba1(0);
|
||||||
|
test_ba1(10);
|
||||||
|
test_ba1(20);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue