Commit 616abc82 authored by Bradley C. Kuszmaul's avatar Bradley C. Kuszmaul Committed by Yoni Fogel

Incorporate blocknum code from 1080a. Runs a little, need a big run on...

Incorporate blocknum code from 1080a.  Runs a little, need a big run on coyote.  Addresses #1000, #1080, #1131.

git-svn-id: file:///svn/tokudb.1131b+1080a@6025 c7de825b-a66e-492c-adef-691d508d4ae1
parent 287767a3
...@@ -39,7 +39,7 @@ enum { BUFFER_HEADER_SIZE = (4 // height// ...@@ -39,7 +39,7 @@ enum { BUFFER_HEADER_SIZE = (4 // height//
struct brtnode_nonleaf_childinfo { struct brtnode_nonleaf_childinfo {
u_int32_t subtree_fingerprint; u_int32_t subtree_fingerprint;
u_int64_t leafentry_estimate; // estimate how many leafentries are below us. u_int64_t leafentry_estimate; // estimate how many leafentries are below us.
DISKOFF diskoff; BLOCKNUM blocknum;
BOOL have_fullhash; // do we have the full hash? BOOL have_fullhash; // do we have the full hash?
u_int32_t fullhash; // the fullhash of the child u_int32_t fullhash; // the fullhash of the child
FIFO buffer; FIFO buffer;
...@@ -53,7 +53,7 @@ struct brtnode { ...@@ -53,7 +53,7 @@ struct brtnode {
unsigned int nodesize; unsigned int nodesize;
int ever_been_written; int ever_been_written;
unsigned int flags; unsigned int flags;
DISKOFF thisnodename; // The size of the node allocated on disk. Not all is necessarily in use. BLOCKNUM thisnodename; // Which block number is this node?
// These two LSNs are used to decide when to make a copy of a node instead of overwriting it. // These two LSNs are used to decide when to make a copy of a node instead of overwriting it.
// In the TOKULOGGER is a field called checkpoint_lsn which is the lsn of the most recent checkpoint // In the TOKULOGGER is a field called checkpoint_lsn which is the lsn of the most recent checkpoint
LSN disk_lsn; // The LSN as of the most recent version on disk. (Updated by brt-serialize) This lsn is saved in the node. LSN disk_lsn; // The LSN as of the most recent version on disk. (Updated by brt-serialize) This lsn is saved in the node.
...@@ -80,7 +80,7 @@ struct brtnode { ...@@ -80,7 +80,7 @@ struct brtnode {
#define BNC_SUBTREE_FINGERPRINT(node,i) ((node)->u.n.childinfos[i].subtree_fingerprint) #define BNC_SUBTREE_FINGERPRINT(node,i) ((node)->u.n.childinfos[i].subtree_fingerprint)
#define BNC_SUBTREE_LEAFENTRY_ESTIMATE(node,i) ((node)->u.n.childinfos[i].leafentry_estimate) #define BNC_SUBTREE_LEAFENTRY_ESTIMATE(node,i) ((node)->u.n.childinfos[i].leafentry_estimate)
#define BNC_DISKOFF(node,i) ((node)->u.n.childinfos[i].diskoff) #define BNC_BLOCKNUM(node,i) ((node)->u.n.childinfos[i].blocknum)
#define BNC_BUFFER(node,i) ((node)->u.n.childinfos[i].buffer) #define BNC_BUFFER(node,i) ((node)->u.n.childinfos[i].buffer)
#define BNC_NBYTESINBUF(node,i) ((node)->u.n.childinfos[i].n_bytes_in_buffer) #define BNC_NBYTESINBUF(node,i) ((node)->u.n.childinfos[i].n_bytes_in_buffer)
#define BNC_HAVE_FULLHASH(node,i) ((node)->u.n.childinfos[i].have_fullhash) #define BNC_HAVE_FULLHASH(node,i) ((node)->u.n.childinfos[i].have_fullhash)
...@@ -109,7 +109,7 @@ enum { ...@@ -109,7 +109,7 @@ enum {
struct remembered_hash { struct remembered_hash {
BOOL valid; // set to FALSE if the fullhash is invalid BOOL valid; // set to FALSE if the fullhash is invalid
FILENUM fnum; FILENUM fnum;
DISKOFF root; BLOCKNUM root;
u_int32_t fullhash; // fullhash is the hashed value of fnum and root. u_int32_t fullhash; // fullhash is the hashed value of fnum and root.
}; };
...@@ -118,15 +118,19 @@ struct brt_header { ...@@ -118,15 +118,19 @@ struct brt_header {
u_int32_t fullhash; u_int32_t fullhash;
int layout_version; int layout_version;
unsigned int nodesize; unsigned int nodesize;
DISKOFF freelist;
DISKOFF unused_memory;
int n_named_roots; /* -1 if the only one is unnamed */ int n_named_roots; /* -1 if the only one is unnamed */
char **names; // an array of names. NULL if subdatabases are not allowed. char **names; // an array of names. NULL if subdatabases are not allowed.
DISKOFF *roots; // an array of DISKOFFs. Element 0 holds the element if no subdatabases allowed. BLOCKNUM *roots; // An array of the roots of the various dictionaries. Element 0 holds the element if no subdatabases allowed.
struct remembered_hash *root_hashes; // an array of hashes of the root offsets. struct remembered_hash *root_hashes; // an array of hashes of the root offsets.
unsigned int *flags_array; // an array of flags. Element 0 holds the element if no subdatabases allowed. unsigned int *flags_array; // an array of flags. Element 0 holds the element if no subdatabases allowed.
FIFO fifo; // all the abort and commit commands. If the header gets flushed to disk, we write the fifo contents beyond the unused_memory. FIFO fifo; // all the abort and commit commands. If the header gets flushed to disk, we write the fifo contents beyond the unused_memory.
// This is the map from block numbers to offsets
//int n_blocks, n_blocks_array_size;
//struct block_descriptor *blocks;
BLOCKNUM free_blocks; // free list for blocks. Use -1 to indicate that there are no free blocks
BLOCKNUM unused_blocks; // first unused block
}; };
struct brt { struct brt {
...@@ -153,8 +157,8 @@ struct brt { ...@@ -153,8 +157,8 @@ struct brt {
}; };
/* serialization code */ /* serialization code */
void toku_serialize_brtnode_to(int fd, DISKOFF off, BRTNODE node); void toku_serialize_brtnode_to(int fd, BLOCKNUM, BRTNODE node);
int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t /*fullhash*/, BRTNODE *brtnode); int toku_deserialize_brtnode_from (int fd, BLOCKNUM off, u_int32_t /*fullhash*/, BRTNODE *brtnode, int tree_node_size);
unsigned int toku_serialize_brtnode_size(BRTNODE node); /* How much space will it take? */ unsigned int toku_serialize_brtnode_size(BRTNODE node); /* How much space will it take? */
int toku_keycompare (bytevec key1, ITEMLEN key1len, bytevec key2, ITEMLEN key2len); int toku_keycompare (bytevec key1, ITEMLEN key1len, bytevec key2, ITEMLEN key2len);
...@@ -163,7 +167,7 @@ void toku_verify_counts(BRTNODE); ...@@ -163,7 +167,7 @@ void toku_verify_counts(BRTNODE);
int toku_serialize_brt_header_size (struct brt_header *h); int toku_serialize_brt_header_size (struct brt_header *h);
int toku_serialize_brt_header_to (int fd, struct brt_header *h); int toku_serialize_brt_header_to (int fd, struct brt_header *h);
int toku_serialize_brt_header_to_wbuf (struct wbuf *, struct brt_header *h); int toku_serialize_brt_header_to_wbuf (struct wbuf *, struct brt_header *h);
int toku_deserialize_brtheader_from (int fd, DISKOFF off, u_int32_t fullhash, struct brt_header **brth); int toku_deserialize_brtheader_from (int fd, BLOCKNUM off, u_int32_t fullhash, struct brt_header **brth);
int toku_serialize_fifo_at (int fd, off_t freeoff, FIFO fifo); // Write a fifo into a disk, without worrying about fitting it into a block. This write is done at the end of the file. int toku_serialize_fifo_at (int fd, off_t freeoff, FIFO fifo); // Write a fifo into a disk, without worrying about fitting it into a block. This write is done at the end of the file.
int toku_deserialize_fifo_at (int fd, off_t at, FIFO *fifo); int toku_deserialize_fifo_at (int fd, off_t at, FIFO *fifo);
...@@ -219,12 +223,12 @@ int toku_unpin_brtnode (BRT brt, BRTNODE node); ...@@ -219,12 +223,12 @@ int toku_unpin_brtnode (BRT brt, BRTNODE node);
unsigned int toku_brtnode_which_child (BRTNODE node , DBT *k, DBT *d, BRT t); unsigned int toku_brtnode_which_child (BRTNODE node , DBT *k, DBT *d, BRT t);
/* Stuff for testing */ /* Stuff for testing */
int toku_testsetup_leaf(BRT brt, DISKOFF *diskoff); int toku_testsetup_leaf(BRT brt, BLOCKNUM *);
int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_children, DISKOFF *children, u_int32_t *subtree_fingerprints, char **keys, int *keylens); int toku_testsetup_nonleaf (BRT brt, int height, BLOCKNUM *diskoff, int n_children, BLOCKNUM *children, u_int32_t *subtree_fingerprints, char **keys, int *keylens);
int toku_testsetup_root(BRT brt, DISKOFF diskoff); int toku_testsetup_root(BRT brt, BLOCKNUM);
int toku_testsetup_get_sersize(BRT brt, DISKOFF diskoff); // Return the size on disk. int toku_testsetup_get_sersize(BRT brt, BLOCKNUM); // Return the size on disk.
int toku_testsetup_insert_to_leaf (BRT brt, DISKOFF diskoff, char *key, int keylen, char *val, int vallen, u_int32_t *leaf_fingerprint); int toku_testsetup_insert_to_leaf (BRT brt, BLOCKNUM, char *key, int keylen, char *val, int vallen, u_int32_t *leaf_fingerprint);
int toku_testsetup_insert_to_nonleaf (BRT brt, DISKOFF diskoff, enum brt_cmd_type, char *key, int keylen, char *val, int vallen, u_int32_t *subtree_fingerprint); int toku_testsetup_insert_to_nonleaf (BRT brt, BLOCKNUM, enum brt_cmd_type, char *key, int keylen, char *val, int vallen, u_int32_t *subtree_fingerprint);
int toku_set_func_fsync (int (*fsync_function)(int)); int toku_set_func_fsync (int (*fsync_function)(int));
...@@ -243,13 +247,14 @@ void *mempool_malloc_from_omt(OMT omt, struct mempool *mp, size_t size); ...@@ -243,13 +247,14 @@ void *mempool_malloc_from_omt(OMT omt, struct mempool *mp, size_t size);
void toku_verify_all_in_mempool(BRTNODE node); void toku_verify_all_in_mempool(BRTNODE node);
int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, bytevec hirange, ITEMLEN hilen, int recurse) ; int toku_verify_brtnode (BRT brt, BLOCKNUM blocknum, bytevec lorange, ITEMLEN lolen, bytevec hirange, ITEMLEN hilen, int recurse) ;
enum brt_layout_version_e { enum brt_layout_version_e {
BRT_LAYOUT_VERSION_5 = 5, BRT_LAYOUT_VERSION_5 = 5,
BRT_LAYOUT_VERSION_6 = 6, // Diff from 5 to 6: Add leafentry_estimate BRT_LAYOUT_VERSION_6 = 6, // Diff from 5 to 6: Add leafentry_estimate
BRT_LAYOUT_VERSION_7 = 7, // Diff from 6 to 7: Add exact-bit to leafentry_estimate #818, add magic to header #22, add per-subdatase flags #333 BRT_LAYOUT_VERSION_7 = 7, // Diff from 6 to 7: Add exact-bit to leafentry_estimate #818, add magic to header #22, add per-subdatase flags #333
BRT_LAYOUT_VERSION_8 = 8, // Diff from 7 to 8: Use murmur instead of crc32. We are going to make a simplification and stop supporting version 7 and before. Current As of Beta 1.0.6 BRT_LAYOUT_VERSION_8 = 8, // Diff from 7 to 8: Use murmur instead of crc32. We are going to make a simplification and stop supporting version 7 and before. Current As of Beta 1.0.6
BRT_LAYOUT_VERSION_9 = 9, // Diff from 8 to 9: Variable-sized blocks and compression.
BRT_ANTEULTIMATE_VERSION, // the version after the most recent version BRT_ANTEULTIMATE_VERSION, // the version after the most recent version
BRT_LAYOUT_VERSION = BRT_ANTEULTIMATE_VERSION-1 // A hack so I don't have to change this line. BRT_LAYOUT_VERSION = BRT_ANTEULTIMATE_VERSION-1 // A hack so I don't have to change this line.
}; };
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "kv-pair.h" #include "kv-pair.h"
#include "mempool.h" #include "mempool.h"
#include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
...@@ -111,8 +112,9 @@ const int uncompressed_magic_len = (8 // tokuleaf or tokunode ...@@ -111,8 +112,9 @@ const int uncompressed_magic_len = (8 // tokuleaf or tokunode
const int compression_header_len = (4 // compressed_len const int compression_header_len = (4 // compressed_len
+4); // uncompressed_len +4); // uncompressed_len
void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) { void toku_serialize_brtnode_to (int fd, BLOCKNUM blocknum, BRTNODE node) {
//printf("%s:%d serializing\n", __FILE__, __LINE__); //printf("%s:%d serializing\n", __FILE__, __LINE__);
DISKOFF offset = blocknum.b * node->nodesize;
struct wbuf w; struct wbuf w;
int i; int i;
unsigned int calculated_size = toku_serialize_brtnode_size(node) - 8; // don't include the compressed or uncompressed sizes unsigned int calculated_size = toku_serialize_brtnode_size(node) - 8; // don't include the compressed or uncompressed sizes
...@@ -165,7 +167,7 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) { ...@@ -165,7 +167,7 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) {
//printf("%s:%d w.ndone=%d (childkeylen[%d]=%d\n", __FILE__, __LINE__, w.ndone, i, node->childkeylens[i]); //printf("%s:%d w.ndone=%d (childkeylen[%d]=%d\n", __FILE__, __LINE__, w.ndone, i, node->childkeylens[i]);
} }
for (i=0; i<node->u.n.n_children; i++) { for (i=0; i<node->u.n.n_children; i++) {
wbuf_DISKOFF(&w, BNC_DISKOFF(node,i)); wbuf_BLOCKNUM(&w, BNC_BLOCKNUM(node,i));
//printf("%s:%d w.ndone=%d\n", __FILE__, __LINE__, w.ndone); //printf("%s:%d w.ndone=%d\n", __FILE__, __LINE__, w.ndone);
} }
...@@ -185,7 +187,7 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) { ...@@ -185,7 +187,7 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) {
})); }));
} }
//printf("%s:%d check_local_fingerprint=%8x\n", __FILE__, __LINE__, check_local_fingerprint); //printf("%s:%d check_local_fingerprint=%8x\n", __FILE__, __LINE__, check_local_fingerprint);
if (check_local_fingerprint!=node->local_fingerprint) printf("%s:%d node=%lld fingerprint expected=%08x actual=%08x\n", __FILE__, __LINE__, (long long)node->thisnodename, check_local_fingerprint, node->local_fingerprint); if (check_local_fingerprint!=node->local_fingerprint) printf("%s:%d node=%" PRId64 " fingerprint expected=%08x actual=%08x\n", __FILE__, __LINE__, node->thisnodename.b, check_local_fingerprint, node->local_fingerprint);
assert(check_local_fingerprint==node->local_fingerprint); assert(check_local_fingerprint==node->local_fingerprint);
} }
} else { } else {
...@@ -240,7 +242,7 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) { ...@@ -240,7 +242,7 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) {
{ {
// If the node has never been written, then write the whole buffer, including the zeros // If the node has never been written, then write the whole buffer, including the zeros
size_t n_to_write = uncompressed_magic_len + compression_header_len + compressed_len; size_t n_to_write = uncompressed_magic_len + compression_header_len + compressed_len;
ssize_t r=pwrite(fd, compressed_buf, n_to_write, off); ssize_t r=pwrite(fd, compressed_buf, n_to_write, offset);
if (r<0) printf("r=%ld errno=%d\n", (long)r, errno); if (r<0) printf("r=%ld errno=%d\n", (long)r, errno);
assert(r==(ssize_t)n_to_write); assert(r==(ssize_t)n_to_write);
} }
...@@ -251,7 +253,8 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) { ...@@ -251,7 +253,8 @@ void toku_serialize_brtnode_to (int fd, DISKOFF off, BRTNODE node) {
toku_free(compressed_buf); toku_free(compressed_buf);
} }
int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTNODE *brtnode) { int toku_deserialize_brtnode_from (int fd, BLOCKNUM blocknum, u_int32_t fullhash, BRTNODE *brtnode, int tree_node_size) {
DISKOFF offset = blocknum.b * tree_node_size;
TAGMALLOC(BRTNODE, result); TAGMALLOC(BRTNODE, result);
struct rbuf rc; struct rbuf rc;
int i; int i;
...@@ -267,7 +270,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN ...@@ -267,7 +270,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN
u_int32_t uncompressed_size; u_int32_t uncompressed_size;
{ {
// get the compressed size // get the compressed size
r = pread(fd, uncompressed_header, sizeof(uncompressed_header), off); r = pread(fd, uncompressed_header, sizeof(uncompressed_header), offset);
//printf("%s:%d r=%d the datasize=%d\n", __FILE__, __LINE__, r, ntohl(datasize_n)); //printf("%s:%d r=%d the datasize=%d\n", __FILE__, __LINE__, r, ntohl(datasize_n));
if (r!=(int)sizeof(uncompressed_header)) { if (r!=(int)sizeof(uncompressed_header)) {
if (r==-1) r=errno; if (r==-1) r=errno;
...@@ -285,7 +288,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN ...@@ -285,7 +288,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN
assert(compressed_data); assert(compressed_data);
{ {
ssize_t rlen=pread(fd, compressed_data, compressed_size, off+uncompressed_magic_len + compression_header_len); ssize_t rlen=pread(fd, compressed_data, compressed_size, offset+uncompressed_magic_len + compression_header_len);
//printf("%s:%d pread->%d datasize=%d\n", __FILE__, __LINE__, r, datasize); //printf("%s:%d pread->%d datasize=%d\n", __FILE__, __LINE__, r, datasize);
assert((size_t)rlen==compressed_size); assert((size_t)rlen==compressed_size);
//printf("Got %d %d %d %d\n", rc.buf[0], rc.buf[1], rc.buf[2], rc.buf[3]); //printf("Got %d %d %d %d\n", rc.buf[0], rc.buf[1], rc.buf[2], rc.buf[3]);
...@@ -324,7 +327,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN ...@@ -324,7 +327,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN
result->layout_version = rbuf_int(&rc); result->layout_version = rbuf_int(&rc);
{ {
switch (result->layout_version) { switch (result->layout_version) {
case BRT_LAYOUT_VERSION_8: goto ok_layout_version; case BRT_LAYOUT_VERSION_9: goto ok_layout_version;
// Don't support older versions. // Don't support older versions.
} }
r=DB_BADFORMAT; r=DB_BADFORMAT;
...@@ -335,7 +338,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN ...@@ -335,7 +338,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN
result->nodesize = rbuf_int(&rc); result->nodesize = rbuf_int(&rc);
result->log_lsn = result->disk_lsn; result->log_lsn = result->disk_lsn;
result->thisnodename = off; result->thisnodename = blocknum;
result->flags = rbuf_int(&rc); result->flags = rbuf_int(&rc);
result->height = rbuf_int(&rc); result->height = rbuf_int(&rc);
result->rand4fingerprint = rbuf_int(&rc); result->rand4fingerprint = rbuf_int(&rc);
...@@ -376,7 +379,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN ...@@ -376,7 +379,7 @@ int toku_deserialize_brtnode_from (int fd, DISKOFF off, u_int32_t fullhash, BRTN
result->u.n.totalchildkeylens+=toku_brtnode_pivot_key_len(result, result->u.n.childkeys[i]); result->u.n.totalchildkeylens+=toku_brtnode_pivot_key_len(result, result->u.n.childkeys[i]);
} }
for (i=0; i<result->u.n.n_children; i++) { for (i=0; i<result->u.n.n_children; i++) {
BNC_DISKOFF(result,i) = rbuf_diskoff(&rc); BNC_BLOCKNUM(result,i) = rbuf_blocknum(&rc);
BNC_HAVE_FULLHASH(result, i) = FALSE; BNC_HAVE_FULLHASH(result, i) = FALSE;
BNC_NBYTESINBUF(result,i) = 0; BNC_NBYTESINBUF(result,i) = 0;
//printf("Child %d at %lld\n", i, result->children[i]); //printf("Child %d at %lld\n", i, result->children[i]);
...@@ -567,21 +570,21 @@ int toku_serialize_brt_header_to_wbuf (struct wbuf *wbuf, struct brt_header *h) ...@@ -567,21 +570,21 @@ int toku_serialize_brt_header_to_wbuf (struct wbuf *wbuf, struct brt_header *h)
wbuf_int (wbuf, size); wbuf_int (wbuf, size);
wbuf_int (wbuf, BRT_LAYOUT_VERSION); wbuf_int (wbuf, BRT_LAYOUT_VERSION);
wbuf_int (wbuf, h->nodesize); wbuf_int (wbuf, h->nodesize);
wbuf_DISKOFF(wbuf, h->freelist); wbuf_BLOCKNUM(wbuf, h->free_blocks);
wbuf_DISKOFF(wbuf, h->unused_memory); wbuf_BLOCKNUM(wbuf, h->unused_blocks);
wbuf_int (wbuf, h->n_named_roots); wbuf_int (wbuf, h->n_named_roots);
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++) {
char *s = h->names[i]; char *s = h->names[i];
unsigned int l = 1+strlen(s); unsigned int l = 1+strlen(s);
wbuf_DISKOFF(wbuf, h->roots[i]); wbuf_BLOCKNUM(wbuf, h->roots[i]);
wbuf_int (wbuf, h->flags_array[i]); wbuf_int (wbuf, h->flags_array[i]);
wbuf_bytes (wbuf, s, l); wbuf_bytes (wbuf, s, l);
assert(l>0 && s[l-1]==0); assert(l>0 && s[l-1]==0);
} }
} else { } else {
wbuf_DISKOFF(wbuf, h->roots[0]); wbuf_BLOCKNUM(wbuf, h->roots[0]);
wbuf_int (wbuf, h->flags_array[0]); wbuf_int (wbuf, h->flags_array[0]);
} }
assert(wbuf->ndone<=wbuf->size); assert(wbuf->ndone<=wbuf->size);
...@@ -623,10 +626,11 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct ...@@ -623,10 +626,11 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct
h->dirty=0; h->dirty=0;
h->layout_version = rbuf_int(&rc); h->layout_version = rbuf_int(&rc);
h->nodesize = rbuf_int(&rc); h->nodesize = rbuf_int(&rc);
assert(h->layout_version==BRT_LAYOUT_VERSION_8); assert(h->layout_version==BRT_LAYOUT_VERSION_9);
h->freelist = rbuf_diskoff(&rc); h->free_blocks = rbuf_blocknum(&rc);
h->unused_memory = rbuf_diskoff(&rc); h->unused_blocks = rbuf_blocknum(&rc);
h->n_named_roots = rbuf_int(&rc); h->n_named_roots = rbuf_int(&rc);
h->free_blocks = make_blocknum(-1);
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;
...@@ -636,7 +640,7 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct ...@@ -636,7 +640,7 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct
MALLOC_N(n_to_malloc, h->names); if (h->names==0) { ret=errno; if (0) { died5: if (h->n_named_roots>=0) free(h->names); } goto died4; } MALLOC_N(n_to_malloc, h->names); if (h->names==0) { ret=errno; if (0) { died5: if (h->n_named_roots>=0) free(h->names); } goto died4; }
for (i=0; i<h->n_named_roots; i++) { for (i=0; i<h->n_named_roots; i++) {
h->root_hashes[i].valid = FALSE; h->root_hashes[i].valid = FALSE;
h->roots[i] = rbuf_diskoff(&rc); h->roots[i] = rbuf_blocknum(&rc);
h->flags_array[i] = rbuf_int(&rc); h->flags_array[i] = rbuf_int(&rc);
bytevec nameptr; bytevec nameptr;
unsigned int len; unsigned int len;
...@@ -651,7 +655,7 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct ...@@ -651,7 +655,7 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct
MALLOC_N(n_to_malloc, h->roots); if (h->roots==0) { ret=errno; goto died2; } MALLOC_N(n_to_malloc, h->roots); if (h->roots==0) { ret=errno; goto died2; }
MALLOC_N(n_to_malloc, h->root_hashes); if (h->root_hashes==0) { ret=errno; goto died3; } MALLOC_N(n_to_malloc, h->root_hashes); if (h->root_hashes==0) { ret=errno; goto died3; }
h->names = 0; h->names = 0;
h->roots[0] = rbuf_diskoff(&rc); h->roots[0] = rbuf_blocknum(&rc);
h->root_hashes[0].valid = FALSE; h->root_hashes[0].valid = FALSE;
h->flags_array[0] = rbuf_int(&rc); h->flags_array[0] = rbuf_int(&rc);
} }
...@@ -661,19 +665,20 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct ...@@ -661,19 +665,20 @@ int deserialize_brtheader_7_or_later(u_int32_t size, int fd, DISKOFF off, struct
return 0; return 0;
} }
int toku_deserialize_brtheader_from (int fd, DISKOFF off, u_int32_t fullhash, struct brt_header **brth) { int toku_deserialize_brtheader_from (int fd, BLOCKNUM blocknum, u_int32_t fullhash, struct brt_header **brth) {
//printf("%s:%d calling MALLOC\n", __FILE__, __LINE__); //printf("%s:%d calling MALLOC\n", __FILE__, __LINE__);
assert(off==0); assert(blocknum.b==0);
DISKOFF offset = 0;
//printf("%s:%d malloced %p\n", __FILE__, __LINE__, h); //printf("%s:%d malloced %p\n", __FILE__, __LINE__, h);
char magic[12]; char magic[12];
ssize_t r = pread(fd, magic, 12, off); ssize_t r = pread(fd, magic, 12, offset);
if (r==0) return -1; if (r==0) return -1;
if (r<0) return errno; if (r<0) return errno;
if (r!=12) return EINVAL; if (r!=12) return EINVAL;
assert(memcmp(magic,"tokudata",8)==0); assert(memcmp(magic,"tokudata",8)==0);
// It's version 7 or later, and the magi clooks OK // It's version 7 or later, and the magi clooks OK
return deserialize_brtheader_7_or_later(ntohl(*(int*)(&magic[8])), fd, off, brth, fullhash); return deserialize_brtheader_7_or_later(ntohl(*(int*)(&magic[8])), fd, offset, brth, fullhash);
} }
unsigned int toku_brt_pivot_key_len (BRT brt, struct kv_pair *pk) { unsigned int toku_brt_pivot_key_len (BRT brt, struct kv_pair *pk) {
......
#include "brt-internal.h" #include "brt-internal.h"
#include "toku_assert.h" #include "toku_assert.h"
int toku_testsetup_leaf(BRT brt, DISKOFF *diskoff) { int toku_testsetup_leaf(BRT brt, BLOCKNUM *blocknum) {
BRTNODE node; BRTNODE node;
int r = toku_read_and_pin_brt_header(brt->cf, &brt->h); int r = toku_read_and_pin_brt_header(brt->cf, &brt->h);
if (r!=0) return r; if (r!=0) return r;
toku_create_new_brtnode(brt, &node, 0, (TOKULOGGER)0); toku_create_new_brtnode(brt, &node, 0, (TOKULOGGER)0);
*diskoff = node->thisnodename; *blocknum = node->thisnodename;
r = toku_unpin_brtnode(brt, node); r = toku_unpin_brtnode(brt, node);
if (r!=0) return r; if (r!=0) return r;
r = toku_unpin_brt_header(brt); r = toku_unpin_brt_header(brt);
...@@ -16,7 +16,7 @@ int toku_testsetup_leaf(BRT brt, DISKOFF *diskoff) { ...@@ -16,7 +16,7 @@ int toku_testsetup_leaf(BRT brt, DISKOFF *diskoff) {
} }
// Don't bother to clean up carefully if something goes wrong. (E.g., it's OK to have malloced stuff that hasn't been freed.) // Don't bother to clean up carefully if something goes wrong. (E.g., it's OK to have malloced stuff that hasn't been freed.)
int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_children, DISKOFF *children, u_int32_t *subtree_fingerprints, char **keys, int *keylens) { int toku_testsetup_nonleaf (BRT brt, int height, BLOCKNUM *blocknum, int n_children, BLOCKNUM *children, u_int32_t *subtree_fingerprints, char **keys, int *keylens) {
BRTNODE node; BRTNODE node;
assert(n_children<=BRT_FANOUT); assert(n_children<=BRT_FANOUT);
int r = toku_read_and_pin_brt_header(brt->cf, &brt->h); int r = toku_read_and_pin_brt_header(brt->cf, &brt->h);
...@@ -31,7 +31,7 @@ int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_childre ...@@ -31,7 +31,7 @@ int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_childre
for (i=0; i<n_children; i++) { for (i=0; i<n_children; i++) {
node->u.n.childinfos[i] = (struct brtnode_nonleaf_childinfo){ .subtree_fingerprint = subtree_fingerprints[i], node->u.n.childinfos[i] = (struct brtnode_nonleaf_childinfo){ .subtree_fingerprint = subtree_fingerprints[i],
.leafentry_estimate = 0, .leafentry_estimate = 0,
.diskoff = children[i], .blocknum = children[i],
.n_bytes_in_buffer = 0 }; .n_bytes_in_buffer = 0 };
r = toku_fifo_create(&BNC_BUFFER(node,i)); if (r!=0) return r; r = toku_fifo_create(&BNC_BUFFER(node,i)); if (r!=0) return r;
} }
...@@ -39,7 +39,7 @@ int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_childre ...@@ -39,7 +39,7 @@ int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_childre
node->u.n.childkeys[i] = kv_pair_malloc(keys[i], keylens[i], 0, 0); node->u.n.childkeys[i] = kv_pair_malloc(keys[i], keylens[i], 0, 0);
node->u.n.totalchildkeylens += keylens[i]; node->u.n.totalchildkeylens += keylens[i];
} }
*diskoff = node->thisnodename; *blocknum = node->thisnodename;
r = toku_unpin_brtnode(brt, node); r = toku_unpin_brtnode(brt, node);
if (r!=0) return r; if (r!=0) return r;
r = toku_unpin_brt_header(brt); r = toku_unpin_brt_header(brt);
...@@ -47,16 +47,16 @@ int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_childre ...@@ -47,16 +47,16 @@ int toku_testsetup_nonleaf (BRT brt, int height, DISKOFF *diskoff, int n_childre
return 0; return 0;
} }
int toku_testsetup_root(BRT brt, DISKOFF diskoff) { int toku_testsetup_root(BRT brt, BLOCKNUM blocknum) {
int r = toku_read_and_pin_brt_header(brt->cf, &brt->h); int r = toku_read_and_pin_brt_header(brt->cf, &brt->h);
if (r!=0) return r; if (r!=0) return r;
brt->h->roots[0] = diskoff; brt->h->roots[0] = blocknum;
brt->h->root_hashes[0].valid = FALSE; brt->h->root_hashes[0].valid = FALSE;
r = toku_unpin_brt_header(brt); r = toku_unpin_brt_header(brt);
return r; return r;
} }
int toku_testsetup_get_sersize(BRT brt, DISKOFF diskoff) // Return the size on disk int toku_testsetup_get_sersize(BRT brt, BLOCKNUM diskoff) // Return the size on disk
{ {
void *node_v; void *node_v;
int r = toku_cachetable_get_and_pin(brt->cf, diskoff, toku_cachetable_hash(brt->cf, diskoff), &node_v, NULL, int r = toku_cachetable_get_and_pin(brt->cf, diskoff, toku_cachetable_hash(brt->cf, diskoff), &node_v, NULL,
...@@ -68,10 +68,10 @@ int toku_testsetup_get_sersize(BRT brt, DISKOFF diskoff) // Return the size on d ...@@ -68,10 +68,10 @@ int toku_testsetup_get_sersize(BRT brt, DISKOFF diskoff) // Return the size on d
return size; return size;
} }
int toku_testsetup_insert_to_leaf (BRT brt, DISKOFF diskoff, char *key, int keylen, char *val, int vallen, u_int32_t *subtree_fingerprint) { int toku_testsetup_insert_to_leaf (BRT brt, BLOCKNUM blocknum, char *key, int keylen, char *val, int vallen, u_int32_t *subtree_fingerprint) {
void *node_v; void *node_v;
int r; int r;
r = toku_cachetable_get_and_pin(brt->cf, diskoff, toku_cachetable_hash(brt->cf, diskoff), &node_v, NULL, r = toku_cachetable_get_and_pin(brt->cf, blocknum, toku_cachetable_hash(brt->cf, blocknum), &node_v, NULL,
toku_brtnode_flush_callback, toku_brtnode_fetch_callback, brt); toku_brtnode_flush_callback, toku_brtnode_fetch_callback, brt);
if (r!=0) return r; if (r!=0) return r;
BRTNODE node=node_v; BRTNODE node=node_v;
...@@ -120,10 +120,10 @@ int toku_testsetup_insert_to_leaf (BRT brt, DISKOFF diskoff, char *key, int keyl ...@@ -120,10 +120,10 @@ int toku_testsetup_insert_to_leaf (BRT brt, DISKOFF diskoff, char *key, int keyl
return r; return r;
} }
int toku_testsetup_insert_to_nonleaf (BRT brt, DISKOFF diskoff, enum brt_cmd_type cmdtype, char *key, int keylen, char *val, int vallen, u_int32_t *subtree_fingerprint) { int toku_testsetup_insert_to_nonleaf (BRT brt, BLOCKNUM blocknum, enum brt_cmd_type cmdtype, char *key, int keylen, char *val, int vallen, u_int32_t *subtree_fingerprint) {
void *node_v; void *node_v;
int r; int r;
r = toku_cachetable_get_and_pin(brt->cf, diskoff, toku_cachetable_hash(brt->cf, diskoff), &node_v, NULL, r = toku_cachetable_get_and_pin(brt->cf, blocknum, toku_cachetable_hash(brt->cf, blocknum), &node_v, NULL,
toku_brtnode_flush_callback, toku_brtnode_fetch_callback, brt); toku_brtnode_flush_callback, toku_brtnode_fetch_callback, brt);
if (r!=0) return r; if (r!=0) return r;
BRTNODE node=node_v; BRTNODE node=node_v;
......
...@@ -59,13 +59,13 @@ static int compare_leafentries (BRT brt, LEAFENTRY a, LEAFENTRY b) { ...@@ -59,13 +59,13 @@ static int compare_leafentries (BRT brt, LEAFENTRY a, LEAFENTRY b) {
return cmp; return cmp;
} }
int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, bytevec hirange, ITEMLEN hilen, int recurse) { int toku_verify_brtnode (BRT brt, BLOCKNUM blocknum, bytevec lorange, ITEMLEN lolen, bytevec hirange, ITEMLEN hilen, int recurse) {
int result=0; int result=0;
BRTNODE node; BRTNODE node;
void *node_v; void *node_v;
int r; int r;
u_int32_t fullhash = toku_cachetable_hash(brt->cf, off); u_int32_t fullhash = toku_cachetable_hash(brt->cf, blocknum);
if ((r = toku_cachetable_get_and_pin(brt->cf, off, fullhash, &node_v, NULL, if ((r = toku_cachetable_get_and_pin(brt->cf, blocknum, fullhash, &node_v, NULL,
toku_brtnode_flush_callback, toku_brtnode_fetch_callback, (void*)(long)brt->h->nodesize))) toku_brtnode_flush_callback, toku_brtnode_fetch_callback, (void*)(long)brt->h->nodesize)))
return r; return r;
//printf("%s:%d pin %p\n", __FILE__, __LINE__, node_v); //printf("%s:%d pin %p\n", __FILE__, __LINE__, node_v);
...@@ -128,7 +128,7 @@ int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, b ...@@ -128,7 +128,7 @@ int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, b
if (hirange) assert(brt->compare_fun(brt->db, &k2, toku_fill_dbt(&k3, hirange, hilen)) <=0); if (hirange) assert(brt->compare_fun(brt->db, &k2, toku_fill_dbt(&k3, hirange, hilen)) <=0);
} }
if (recurse) { if (recurse) {
result|=toku_verify_brtnode(brt, BNC_DISKOFF(node, i), result|=toku_verify_brtnode(brt, BNC_BLOCKNUM(node, i),
(i==0) ? lorange : kv_pair_key(node->u.n.childkeys[i-1]), (i==0) ? lorange : kv_pair_key(node->u.n.childkeys[i-1]),
(i==0) ? lolen : toku_brt_pivot_key_len(brt, node->u.n.childkeys[i-1]), (i==0) ? lolen : toku_brt_pivot_key_len(brt, node->u.n.childkeys[i-1]),
(i==node->u.n.n_children-1) ? hirange : kv_pair_key(node->u.n.childkeys[i]), (i==node->u.n.n_children-1) ? hirange : kv_pair_key(node->u.n.childkeys[i]),
...@@ -149,7 +149,7 @@ int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, b ...@@ -149,7 +149,7 @@ int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, b
LEAFENTRY prev=0; LEAFENTRY prev=0;
toku_omt_iterate(node->u.l.buffer, check_increasing, &prev); toku_omt_iterate(node->u.l.buffer, check_increasing, &prev);
} }
if ((r = toku_cachetable_unpin(brt->cf, off, fullhash, 0, 0))) return r; if ((r = toku_cachetable_unpin(brt->cf, blocknum, fullhash, 0, 0))) return r;
return result; return result;
} }
......
This diff is collapsed.
...@@ -26,30 +26,30 @@ void print_item (bytevec val, ITEMLEN len) { ...@@ -26,30 +26,30 @@ void print_item (bytevec val, ITEMLEN len) {
void dump_header (int f, struct brt_header **header) { void dump_header (int f, struct brt_header **header) {
struct brt_header *h; struct brt_header *h;
int r; int r;
r = toku_deserialize_brtheader_from (f, 0, 0/*pass 0 for hash. It doesn't matter.*/, &h); assert(r==0); r = toku_deserialize_brtheader_from (f, header_blocknum, 0/*pass 0 for hash. It doesn't matter.*/, &h); assert(r==0);
printf("brtheader:\n"); printf("brtheader:\n");
if (h->layout_version==BRT_LAYOUT_VERSION_6) printf(" layout_version<=6\n"); if (h->layout_version==BRT_LAYOUT_VERSION_6) printf(" layout_version<=6\n");
else printf(" layout_version=%d\n", h->layout_version); else printf(" layout_version=%d\n", h->layout_version);
printf(" dirty=%d\n", h->dirty); printf(" dirty=%d\n", h->dirty);
printf(" nodesize=%d\n", h->nodesize); printf(" nodesize=%d\n", h->nodesize);
printf(" freelist=%lld\n", h->freelist); printf(" free_blocks=%" PRId64 "\n", h->free_blocks.b);
printf(" unused_memory=%lld\n", h->unused_memory); printf(" unused_memory=%" PRId64 "\n", h->unused_blocks.b);
if (h->n_named_roots==-1) { if (h->n_named_roots==-1) {
printf(" unnamed_root=%lld\n", h->roots[0]); printf(" unnamed_root=%" PRId64 "\n", h->roots[0].b);
printf(" flags=%d\n", h->flags_array[0]); printf(" flags=%d\n", h->flags_array[0]);
} else { } else {
printf(" n_named_roots=%d\n", h->n_named_roots); printf(" n_named_roots=%d\n", h->n_named_roots);
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++) {
printf(" %s -> %lld\n", h->names[i], h->roots[i]); printf(" %s -> %" PRId64 "\n", h->names[i], h->roots[i].b);
printf(" flags=%d\n", h->flags_array[i]); printf(" flags=%d\n", h->flags_array[i]);
} }
} }
} }
*header = h; *header = h;
printf("Fifo:\n"); printf("Fifo:\n");
r = toku_deserialize_fifo_at(f, h->unused_memory, &h->fifo); r = toku_deserialize_fifo_at(f, h->unused_blocks.b*h->nodesize, &h->fifo);
printf(" fifo has %d entries\n", toku_fifo_n_entries(h->fifo)); printf(" fifo has %d entries\n", toku_fifo_n_entries(h->fifo));
if (dump_data) { if (dump_data) {
FIFO_ITERATE(h->fifo, key, keylen, data, datalen, type, xid, FIFO_ITERATE(h->fifo, key, keylen, data, datalen, type, xid,
...@@ -83,16 +83,16 @@ int print_le(OMTVALUE lev, u_int32_t UU(idx), void *UU(v)) { ...@@ -83,16 +83,16 @@ int print_le(OMTVALUE lev, u_int32_t UU(idx), void *UU(v)) {
return 0; return 0;
} }
void dump_node (int f, DISKOFF off) { void dump_node (int f, BLOCKNUM blocknum, int tree_node_size) {
BRTNODE n; BRTNODE n;
int r = toku_deserialize_brtnode_from (f, off, 0 /*pass zero for hash, it doesn't matter*/, &n); int r = toku_deserialize_brtnode_from (f, blocknum, 0 /*pass zero for hash, it doesn't matter*/, &n, tree_node_size);
assert(r==0); assert(r==0);
assert(n!=0); assert(n!=0);
printf("brtnode\n"); printf("brtnode\n");
printf(" nodesize =%u\n", n->nodesize); printf(" nodesize =%u\n", n->nodesize);
printf(" sizeonddisk =%d\n", toku_serialize_brtnode_size(n)); printf(" sizeonddisk =%d\n", toku_serialize_brtnode_size(n));
printf(" flags =%u\n", n->flags); printf(" flags =%u\n", n->flags);
printf(" thisnodename=%lld\n", n->thisnodename); printf(" thisnodename=%" PRId64 "\n", n->thisnodename.b);
printf(" disk_lsn =%" PRId64 "\n", n->disk_lsn.lsn); printf(" disk_lsn =%" PRId64 "\n", n->disk_lsn.lsn);
//printf(" log_lsn =%lld\n", n->log_lsn.lsn); // The log_lsn is a memory-only value. //printf(" log_lsn =%lld\n", n->log_lsn.lsn); // The log_lsn is a memory-only value.
printf(" height =%d\n", n->height); printf(" height =%d\n", n->height);
...@@ -126,7 +126,7 @@ void dump_node (int f, DISKOFF off) { ...@@ -126,7 +126,7 @@ void dump_node (int f, DISKOFF off) {
} }
printf(" children:\n"); printf(" children:\n");
for (i=0; i<n->u.n.n_children; i++) { for (i=0; i<n->u.n.n_children; i++) {
printf(" child %d: %lld\n", i, BNC_DISKOFF(n, i)); printf(" child %d: %" PRId64 "\n", i, BNC_BLOCKNUM(n, i).b);
printf(" buffer contains %d bytes (%d items)\n", BNC_NBYTESINBUF(n, i), toku_fifo_n_entries(BNC_BUFFER(n,i))); printf(" buffer contains %d bytes (%d items)\n", BNC_NBYTESINBUF(n, i), toku_fifo_n_entries(BNC_BUFFER(n,i)));
if (dump_data) { if (dump_data) {
FIFO_ITERATE(BNC_BUFFER(n,i), key, keylen, data, datalen, typ, xid, FIFO_ITERATE(BNC_BUFFER(n,i), key, keylen, data, datalen, typ, xid,
...@@ -180,9 +180,9 @@ int main (int argc, const char *argv[]) { ...@@ -180,9 +180,9 @@ int main (int argc, const char *argv[]) {
int f = open(n, O_RDONLY); assert(f>=0); int f = open(n, O_RDONLY); assert(f>=0);
struct brt_header *h; struct brt_header *h;
dump_header(f, &h); dump_header(f, &h);
DISKOFF off; BLOCKNUM blocknum;
for (off=h->nodesize; off<h->unused_memory; off+=h->nodesize) { for (blocknum.b=1; blocknum.b<h->unused_blocks.b; blocknum.b++) {
dump_node(f, off); dump_node(f, blocknum, h->nodesize);
} }
toku_brtheader_free(h); toku_brtheader_free(h);
toku_malloc_cleanup(); toku_malloc_cleanup();
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#include "../include/db.h" #include "../include/db.h"
#include <inttypes.h>
typedef struct brt *BRT; typedef struct brt *BRT;
struct brt_header; struct brt_header;
...@@ -21,6 +22,10 @@ typedef const void *bytevec; ...@@ -21,6 +22,10 @@ typedef const void *bytevec;
typedef long long DISKOFF; /* Offset in a disk. -1 is the NULL pointer. */ typedef long long 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.
static inline BLOCKNUM make_blocknum(int64_t b) { BLOCKNUM result={b}; return result; }
static const BLOCKNUM header_blocknum = {0};
typedef struct { typedef struct {
u_int32_t len; u_int32_t len;
...@@ -46,16 +51,16 @@ typedef struct loggedbrtheader { ...@@ -46,16 +51,16 @@ typedef struct loggedbrtheader {
u_int32_t size; u_int32_t size;
u_int32_t flags; u_int32_t flags;
u_int32_t nodesize; u_int32_t nodesize;
DISKOFF freelist; BLOCKNUM free_blocks;
DISKOFF unused_memory; BLOCKNUM unused_blocks;
int32_t n_named_roots; // -1 for the union below to be "one". int32_t n_named_roots; // -1 for the union below to be "one".
union { union {
struct { struct {
char **names; char **names;
DISKOFF *roots; BLOCKNUM *roots;
} many; } many;
struct { struct {
DISKOFF root; BLOCKNUM root;
} one; } one;
} u; } u;
} LOGGEDBRTHEADER; } LOGGEDBRTHEADER;
......
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved." #ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
#include <errno.h> #include <errno.h>
#include <malloc.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <pthread.h> #include <unistd.h>
#include "cachetable.h" #include "cachetable.h"
#include "hashfun.h" #include "hashfun.h"
...@@ -17,7 +18,6 @@ ...@@ -17,7 +18,6 @@
#include "log_header.h" #include "log_header.h"
#include "threadpool.h" #include "threadpool.h"
#include "cachetable-rwlock.h" #include "cachetable-rwlock.h"
#include <malloc.h>
// execute the cachetable callbacks using a writer thread 0->no 1->yes // execute the cachetable callbacks using a writer thread 0->no 1->yes
#define DO_WRITER_THREAD 1 #define DO_WRITER_THREAD 1
...@@ -233,7 +233,7 @@ int toku_cachetable_openfd (CACHEFILE *cf, CACHETABLE t, int fd, const char *fna ...@@ -233,7 +233,7 @@ int toku_cachetable_openfd (CACHEFILE *cf, CACHETABLE t, int fd, const char *fna
newcf->filenum.fileid = next_filenum_to_use.fileid++; newcf->filenum.fileid = next_filenum_to_use.fileid++;
cachefile_init_filenum(newcf, fd, fname, fileid); cachefile_init_filenum(newcf, fd, fname, fileid);
newcf->refcount = 1; newcf->refcount = 1;
newcf->header_fullhash = toku_cachetable_hash(newcf, 0); newcf->header_fullhash = toku_cachetable_hash(newcf, header_blocknum);
newcf->next = t->cachefiles; newcf->next = t->cachefiles;
t->cachefiles = newcf; t->cachefiles = newcf;
*cf = newcf; *cf = newcf;
...@@ -340,7 +340,7 @@ int toku_cachetable_assert_all_unpinned (CACHETABLE t) { ...@@ -340,7 +340,7 @@ int toku_cachetable_assert_all_unpinned (CACHETABLE t) {
for (p=t->table[i]; p; p=p->hash_chain) { for (p=t->table[i]; p; p=p->hash_chain) {
assert(ctpair_pinned(&p->rwlock)>=0); assert(ctpair_pinned(&p->rwlock)>=0);
if (ctpair_pinned(&p->rwlock)) { if (ctpair_pinned(&p->rwlock)) {
printf("%s:%d pinned: %lld (%p)\n", __FILE__, __LINE__, p->key, p->value); printf("%s:%d pinned: %" PRId64 " (%p)\n", __FILE__, __LINE__, p->key.b, p->value);
some_pinned=1; some_pinned=1;
} }
} }
...@@ -359,7 +359,7 @@ int toku_cachefile_count_pinned (CACHEFILE cf, int print_them) { ...@@ -359,7 +359,7 @@ int toku_cachefile_count_pinned (CACHEFILE cf, int print_them) {
for (p=t->table[i]; p; p=p->hash_chain) { for (p=t->table[i]; p; p=p->hash_chain) {
assert(ctpair_pinned(&p->rwlock)>=0); assert(ctpair_pinned(&p->rwlock)>=0);
if (ctpair_pinned(&p->rwlock) && (cf==0 || p->cachefile==cf)) { if (ctpair_pinned(&p->rwlock) && (cf==0 || p->cachefile==cf)) {
if (print_them) printf("%s:%d pinned: %lld (%p)\n", __FILE__, __LINE__, p->key, p->value); if (print_them) printf("%s:%d pinned: %"PRId64" (%p)\n", __FILE__, __LINE__, p->key.b, p->value);
n_pinned++; n_pinned++;
} }
} }
...@@ -386,10 +386,10 @@ static inline u_int32_t final (u_int32_t a, u_int32_t b, u_int32_t c) { ...@@ -386,10 +386,10 @@ static inline u_int32_t final (u_int32_t a, u_int32_t b, u_int32_t c) {
return c; return c;
} }
u_int32_t toku_cachetable_hash (CACHEFILE cachefile, CACHEKEY key) u_int32_t toku_cachetable_hash (CACHEFILE cachefile, BLOCKNUM key)
// Effect: Return a 32-bit hash key. The hash key shall be suitable for using with bitmasking for a table of size power-of-two. // Effect: Return a 32-bit hash key. The hash key shall be suitable for using with bitmasking for a table of size power-of-two.
{ {
return final(cachefile->filenum.fileid, (u_int32_t)(key>>32), (u_int32_t)key); return final(cachefile->filenum.fileid, (u_int32_t)(key.b>>32), (u_int32_t)key.b);
} }
#if 0 #if 0
...@@ -708,7 +708,7 @@ int toku_cachetable_put(CACHEFILE cachefile, CACHEKEY key, u_int32_t fullhash, v ...@@ -708,7 +708,7 @@ int toku_cachetable_put(CACHEFILE cachefile, CACHEKEY key, u_int32_t fullhash, v
PAIR p; PAIR p;
for (p=ct->table[fullhash&(cachefile->cachetable->table_size-1)]; p; p=p->hash_chain) { for (p=ct->table[fullhash&(cachefile->cachetable->table_size-1)]; p; p=p->hash_chain) {
count++; count++;
if (p->key==key && p->cachefile==cachefile) { if (p->key.b==key.b && p->cachefile==cachefile) {
// Semantically, these two asserts are not strictly right. After all, when are two functions eq? // Semantically, these two asserts are not strictly right. After all, when are two functions eq?
// In practice, the functions better be the same. // In practice, the functions better be the same.
assert(p->flush_callback==flush_callback); assert(p->flush_callback==flush_callback);
...@@ -742,7 +742,7 @@ int toku_cachetable_get_and_pin(CACHEFILE cachefile, CACHEKEY key, u_int32_t ful ...@@ -742,7 +742,7 @@ int toku_cachetable_get_and_pin(CACHEFILE cachefile, CACHEKEY key, u_int32_t ful
cachetable_wait_write(t); cachetable_wait_write(t);
for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) { for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) {
count++; count++;
if (p->key==key && p->cachefile==cachefile) { if (p->key.b==key.b && p->cachefile==cachefile) {
*value = p->value; *value = p->value;
if (sizep) *sizep = p->size; if (sizep) *sizep = p->size;
ctpair_read_lock(&p->rwlock, &t->mutex); ctpair_read_lock(&p->rwlock, &t->mutex);
...@@ -783,7 +783,8 @@ int toku_cachetable_maybe_get_and_pin (CACHEFILE cachefile, CACHEKEY key, u_int3 ...@@ -783,7 +783,8 @@ int toku_cachetable_maybe_get_and_pin (CACHEFILE cachefile, CACHEKEY key, u_int3
cachetable_lock(t); cachetable_lock(t);
for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) { for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) {
count++; count++;
if (p->key==key && p->cachefile==cachefile && !p->writing) { if (p->key.b==key.b && p->cachefile==cachefile && !p->writing) {
note_hash_count(count);
*value = p->value; *value = p->value;
ctpair_read_lock(&p->rwlock, &t->mutex); ctpair_read_lock(&p->rwlock, &t->mutex);
lru_touch(t,p); lru_touch(t,p);
...@@ -809,7 +810,7 @@ int toku_cachetable_unpin(CACHEFILE cachefile, CACHEKEY key, u_int32_t fullhash, ...@@ -809,7 +810,7 @@ int toku_cachetable_unpin(CACHEFILE cachefile, CACHEKEY key, u_int32_t fullhash,
cachetable_lock(t); cachetable_lock(t);
for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) { for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) {
count++; count++;
if (p->key==key && p->cachefile==cachefile) { if (p->key.b==key.b && p->cachefile==cachefile) {
assert(p->rwlock.pinned>0); assert(p->rwlock.pinned>0);
ctpair_read_unlock(&p->rwlock); ctpair_read_unlock(&p->rwlock);
p->dirty |= dirty; p->dirty |= dirty;
...@@ -848,7 +849,7 @@ int toku_cachetable_rename (CACHEFILE cachefile, CACHEKEY oldkey, CACHEKEY newke ...@@ -848,7 +849,7 @@ int toku_cachetable_rename (CACHEFILE cachefile, CACHEKEY oldkey, CACHEKEY newke
p; p;
ptr_to_p = &p->hash_chain, p = *ptr_to_p) { ptr_to_p = &p->hash_chain, p = *ptr_to_p) {
count++; count++;
if (p->key==oldkey && p->cachefile==cachefile) { if (p->key.b==oldkey.b && p->cachefile==cachefile) {
note_hash_count(count); note_hash_count(count);
*ptr_to_p = p->hash_chain; *ptr_to_p = p->hash_chain;
p->key = newkey; p->key = newkey;
...@@ -1005,7 +1006,7 @@ int toku_cachetable_remove (CACHEFILE cachefile, CACHEKEY key, int write_me) { ...@@ -1005,7 +1006,7 @@ int toku_cachetable_remove (CACHEFILE cachefile, CACHEKEY key, int write_me) {
cachetable_lock(t); cachetable_lock(t);
for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) { for (p=t->table[fullhash&(t->table_size-1)]; p; p=p->hash_chain) {
count++; count++;
if (p->key==key && p->cachefile==cachefile) { if (p->key.b==key.b && p->cachefile==cachefile) {
flush_and_remove(t, p, write_me); flush_and_remove(t, p, write_me);
if ((4 * t->n_in_table < t->table_size) && (t->table_size>4)) if ((4 * t->n_in_table < t->table_size) && (t->table_size>4))
cachetable_rehash(t, t->table_size/2); cachetable_rehash(t, t->table_size/2);
...@@ -1156,7 +1157,7 @@ void toku_cachetable_print_state (CACHETABLE ct) { ...@@ -1156,7 +1157,7 @@ void toku_cachetable_print_state (CACHETABLE ct) {
if (p != 0) { if (p != 0) {
printf("t[%d]=", i); printf("t[%d]=", i);
for (p=ct->table[i]; p; p=p->hash_chain) { for (p=ct->table[i]; p; p=p->hash_chain) {
printf(" {%lld, %p, dirty=%d, pin=%d, size=%ld}", p->key, p->cachefile, p->dirty, p->rwlock.pinned, p->size); printf(" {%"PRId64", %p, dirty=%d, pin=%d, size=%ld}", p->key.b, p->cachefile, p->dirty, p->rwlock.pinned, p->size);
} }
printf("\n"); printf("\n");
} }
...@@ -1186,7 +1187,8 @@ int toku_cachetable_get_key_state (CACHETABLE ct, CACHEKEY key, CACHEFILE cf, vo ...@@ -1186,7 +1187,8 @@ int toku_cachetable_get_key_state (CACHETABLE ct, CACHEKEY key, CACHEFILE cf, vo
cachetable_lock(ct); cachetable_lock(ct);
for (p = ct->table[fullhash&(ct->table_size-1)]; p; p = p->hash_chain) { for (p = ct->table[fullhash&(ct->table_size-1)]; p; p = p->hash_chain) {
count++; count++;
if (p->key == key && p->cachefile == cf) { if (p->key.b == key.b && p->cachefile == cf) {
note_hash_count(count);
if (value_ptr) if (value_ptr)
*value_ptr = p->value; *value_ptr = p->value;
if (dirty_ptr) if (dirty_ptr)
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* size limit is the upper bound of the sum of size of the entries in the cache table (total number of bytes) * size limit is the upper bound of the sum of size of the entries in the cache table (total number of bytes)
*/ */
typedef long long CACHEKEY; typedef BLOCKNUM CACHEKEY;
// create a new cachetable // create a new cachetable
// returns: if success, 0 is returned and result points to the new cachetable // returns: if success, 0 is returned and result points to the new cachetable
......
...@@ -116,6 +116,9 @@ static inline int toku_logsizeof_FILENUM (FILENUM v __attribute__((__unused__))) ...@@ -116,6 +116,9 @@ static inline int toku_logsizeof_FILENUM (FILENUM v __attribute__((__unused__)))
static inline int toku_logsizeof_DISKOFF (DISKOFF v __attribute__((__unused__))) { static inline int toku_logsizeof_DISKOFF (DISKOFF v __attribute__((__unused__))) {
return 8; return 8;
} }
static inline int toku_logsizeof_BLOCKNUM (BLOCKNUM v __attribute__((__unused__))) {
return 8;
}
static inline int toku_logsizeof_TXNID (TXNID txnid __attribute__((__unused__))) { static inline int toku_logsizeof_TXNID (TXNID txnid __attribute__((__unused__))) {
return 8; return 8;
......
...@@ -618,6 +618,10 @@ int toku_fread_DISKOFF (FILE *f, DISKOFF *diskoff, struct x1764 *checksum, u_int ...@@ -618,6 +618,10 @@ int toku_fread_DISKOFF (FILE *f, DISKOFF *diskoff, struct x1764 *checksum, u_int
int r = toku_fread_u_int64_t (f, (u_int64_t*)diskoff, checksum, len); // sign conversion will be OK. int r = toku_fread_u_int64_t (f, (u_int64_t*)diskoff, checksum, len); // sign conversion will be OK.
return r; return r;
} }
int toku_fread_BLOCKNUM (FILE *f, BLOCKNUM *blocknum, struct x1764 *checksum, u_int32_t *len) {
int r = toku_fread_u_int64_t (f, (u_int64_t*)&blocknum->b, checksum, len); // sign conversion will be OK.
return r;
}
int toku_fread_TXNID (FILE *f, TXNID *txnid, struct x1764 *checksum, u_int32_t *len) { int toku_fread_TXNID (FILE *f, TXNID *txnid, struct x1764 *checksum, u_int32_t *len) {
return toku_fread_u_int64_t (f, txnid, checksum, len); return toku_fread_u_int64_t (f, txnid, checksum, len);
} }
...@@ -644,11 +648,11 @@ int toku_fread_LOGGEDBRTHEADER (FILE *f, LOGGEDBRTHEADER *v, struct x1764 *check ...@@ -644,11 +648,11 @@ int toku_fread_LOGGEDBRTHEADER (FILE *f, LOGGEDBRTHEADER *v, struct x1764 *check
r = toku_fread_u_int32_t(f, &v->size, checksum, len); if (r!=0) return r; r = toku_fread_u_int32_t(f, &v->size, checksum, len); if (r!=0) return r;
r = toku_fread_u_int32_t(f, &v->flags, checksum, len); if (r!=0) return r; r = toku_fread_u_int32_t(f, &v->flags, checksum, len); if (r!=0) return r;
r = toku_fread_u_int32_t(f, &v->nodesize, checksum, len); if (r!=0) return r; r = toku_fread_u_int32_t(f, &v->nodesize, checksum, len); if (r!=0) return r;
r = toku_fread_DISKOFF (f, &v->freelist, checksum, len); if (r!=0) return r; r = toku_fread_BLOCKNUM (f, &v->free_blocks, checksum, len); if (r!=0) return r;
r = toku_fread_DISKOFF (f, &v->unused_memory, checksum, len); if (r!=0) return r; r = toku_fread_BLOCKNUM (f, &v->unused_blocks, checksum, len); if (r!=0) return r;
r = toku_fread_int32_t (f, &v->n_named_roots, checksum, len); if (r!=0) return r; r = toku_fread_int32_t (f, &v->n_named_roots, checksum, len); if (r!=0) return r;
assert(v->n_named_roots==-1); assert(v->n_named_roots==-1);
r = toku_fread_DISKOFF (f, &v->u.one.root, checksum, len); if (r!=0) return r; r = toku_fread_BLOCKNUM (f, &v->u.one.root, checksum, len); if (r!=0) return r;
return 0; return 0;
} }
...@@ -740,11 +744,19 @@ int toku_logprint_DISKOFF (FILE *outf, FILE *inf, const char *fieldname, struct ...@@ -740,11 +744,19 @@ int toku_logprint_DISKOFF (FILE *outf, FILE *inf, const char *fieldname, struct
fprintf(outf, " %s=%lld", fieldname, v); fprintf(outf, " %s=%lld", 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__))) {
BLOCKNUM v;
int r = toku_fread_BLOCKNUM(inf, &v, checksum, len);
if (r!=0) return r;
fprintf(outf, " %s=%"PRId64, fieldname, v.b);
return 0;
}
int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *checksum, u_int32_t *len, const char *format __attribute__((__unused__))) { int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *checksum, u_int32_t *len, const char *format __attribute__((__unused__))) {
LOGGEDBRTHEADER v; LOGGEDBRTHEADER v;
int r = toku_fread_LOGGEDBRTHEADER(inf, &v, checksum, len); int r = toku_fread_LOGGEDBRTHEADER(inf, &v, checksum, len);
if (r!=0) return r; if (r!=0) return r;
fprintf(outf, " %s={size=%d flags=%d nodesize=%d freelist=%lld unused_memory=%lld n_named_roots=%d", fieldname, v.size, v.flags, v.nodesize, v.freelist, v.unused_memory, v.n_named_roots); fprintf(outf, " %s={size=%d flags=%d nodesize=%d free_blocks=%" PRId64 " unused_memory=%" PRId64 " n_named_roots=%d", fieldname, v.size, v.flags, v.nodesize, v.free_blocks.b, v.unused_blocks.b, v.n_named_roots);
return 0; return 0;
} }
......
...@@ -57,6 +57,7 @@ int toku_fread_u_int32_t (FILE *f, u_int32_t *v, struct x1764 *, u_int32_t *len) ...@@ -57,6 +57,7 @@ int toku_fread_u_int32_t (FILE *f, u_int32_t *v, struct x1764 *, u_int32_t *len)
int toku_fread_LSN (FILE *f, LSN *lsn, struct x1764 *, u_int32_t *len); int toku_fread_LSN (FILE *f, LSN *lsn, struct x1764 *, u_int32_t *len);
int toku_fread_FILENUM (FILE *f, FILENUM *filenum, struct x1764 *, u_int32_t *len); int toku_fread_FILENUM (FILE *f, FILENUM *filenum, struct x1764 *, u_int32_t *len);
int toku_fread_DISKOFF (FILE *f, DISKOFF *diskoff, struct x1764 *, u_int32_t *len); int toku_fread_DISKOFF (FILE *f, DISKOFF *diskoff, struct x1764 *, u_int32_t *len);
int toku_fread_BLOCKNUM (FILE *f, BLOCKNUM *, struct x1764 *, u_int32_t *len);
int toku_fread_TXNID (FILE *f, TXNID *txnid, struct x1764 *, u_int32_t *len); int toku_fread_TXNID (FILE *f, TXNID *txnid, struct x1764 *, u_int32_t *len);
// fills in the bs with malloced data. // fills in the bs with malloced data.
int toku_fread_BYTESTRING (FILE *f, BYTESTRING *bs, struct x1764 *, u_int32_t *len); int toku_fread_BYTESTRING (FILE *f, BYTESTRING *bs, struct x1764 *, u_int32_t *len);
...@@ -68,6 +69,7 @@ int toku_logprint_TXNID (FILE *outf, FILE *inf, const char *fieldname, ...@@ -68,6 +69,7 @@ int toku_logprint_TXNID (FILE *outf, FILE *inf, const char *fieldname,
int toku_logprint_BYTESTRING (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *); int toku_logprint_BYTESTRING (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
int toku_logprint_FILENUM (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *); int toku_logprint_FILENUM (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
int toku_logprint_DISKOFF (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *); int toku_logprint_DISKOFF (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
int toku_logprint_BLOCKNUM (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
int toku_logprint_u_int8_t (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *); int toku_logprint_u_int8_t (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
int toku_logprint_u_int32_t (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *); int toku_logprint_u_int32_t (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *); int toku_logprint_LOGGEDBRTHEADER (FILE *outf, FILE *inf, const char *fieldname, struct x1764 *, u_int32_t *len, const char *);
......
...@@ -83,7 +83,7 @@ const struct logtype logtypes[] = { ...@@ -83,7 +83,7 @@ const struct logtype logtypes[] = {
{"xbegin", 'b', FA{{"TXNID", "parenttxnid", 0},NULLFIELD}}, {"xbegin", 'b', FA{{"TXNID", "parenttxnid", 0},NULLFIELD}},
#if 0 #if 0
{"tl_delete", 'D', FA{{"FILENUM", "filenum", 0}, // tl logentries can be used, by themselves, to rebuild the whole DB from scratch. {"tl_delete", 'D', FA{{"FILENUM", "filenum", 0}, // tl logentries can be used, by themselves, to rebuild the whole DB from scratch.
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"BYTESTRING", "key", 0}, {"BYTESTRING", "key", 0},
{"BYTESTRING", "data", 0}, {"BYTESTRING", "data", 0},
NULLFIELD}}, NULLFIELD}},
...@@ -97,46 +97,46 @@ const struct logtype logtypes[] = { ...@@ -97,46 +97,46 @@ const struct logtype logtypes[] = {
{"LOGGEDBRTHEADER", "header", 0}, {"LOGGEDBRTHEADER", "header", 0},
NULLFIELD}}, NULLFIELD}},
{"newbrtnode", 'N', FA{{"FILENUM", "filenum", 0}, {"newbrtnode", 'N', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "height", 0}, {"u_int32_t", "height", 0},
{"u_int32_t", "nodesize", 0}, {"u_int32_t", "nodesize", 0},
{"u_int8_t", "is_dup_sort", 0}, {"u_int8_t", "is_dup_sort", 0},
{"u_int32_t", "rand4fingerprint", "%08x"}, {"u_int32_t", "rand4fingerprint", "%08x"},
NULLFIELD}}, NULLFIELD}},
{"changeunnamedroot", 'u', FA{{"FILENUM", "filenum", 0}, {"changeunnamedroot", 'u', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "oldroot", 0}, {"BLOCKNUM", "oldroot", 0},
{"DISKOFF", "newroot", 0}, {"BLOCKNUM", "newroot", 0},
NULLFIELD}}, NULLFIELD}},
{"changenamedroot", 'n', FA{{"FILENUM", "filenum", 0}, {"changenamedroot", 'n', FA{{"FILENUM", "filenum", 0},
{"BYTESTRING", "name", 0}, {"BYTESTRING", "name", 0},
{"DISKOFF", "oldroot", 0}, {"BLOCKNUM", "oldroot", 0},
{"DISKOFF", "newroot", 0}, {"BLOCKNUM", "newroot", 0},
NULLFIELD}}, NULLFIELD}},
{"changeunusedmemory", 'm', FA{{"FILENUM", "filenum", 0}, {"changeunusedmemory", 'm', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "oldunused", 0}, {"BLOCKNUM", "oldunused", 0},
{"DISKOFF", "newunused", 0}, {"BLOCKNUM", "newunused", 0},
NULLFIELD}}, NULLFIELD}},
{"addchild", 'c', FA{{"FILENUM", "filenum", 0}, {"addchild", 'c', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "childnum", 0}, // children scoot over {"u_int32_t", "childnum", 0}, // children scoot over
{"DISKOFF", "child", 0}, {"BLOCKNUM", "child", 0},
{"u_int32_t", "childfingerprint", "%08x"}, {"u_int32_t", "childfingerprint", "%08x"},
NULLFIELD}}, NULLFIELD}},
{"delchild", 'r', FA{{"FILENUM", "filenum", 0}, {"delchild", 'r', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "childnum", 0}, // children scoot over {"u_int32_t", "childnum", 0}, // children scoot over
{"DISKOFF", "child", 0}, {"BLOCKNUM", "child", 0},
{"u_int32_t", "childfingerprint", "%08x"}, {"u_int32_t", "childfingerprint", "%08x"},
{"BYTESTRING", "pivotkey", 0}, {"BYTESTRING", "pivotkey", 0},
NULLFIELD}}, NULLFIELD}},
{"setchild", 'i', FA{{"FILENUM", "filenum", 0}, {"setchild", 'i', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "childnum", 0}, {"u_int32_t", "childnum", 0},
{"DISKOFF", "oldchild", 0}, {"BLOCKNUM", "oldchild", 0},
{"DISKOFF", "newchild", 0}, {"BLOCKNUM", "newchild", 0},
NULLFIELD}}, NULLFIELD}},
{"setpivot", 'k', FA{{"FILENUM", "filenum", 0}, {"setpivot", 'k', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "childnum", 0}, {"u_int32_t", "childnum", 0},
{"BYTESTRING", "pivotkey", 0}, {"BYTESTRING", "pivotkey", 0},
NULLFIELD}}, NULLFIELD}},
...@@ -152,11 +152,11 @@ const struct logtype logtypes[] = { ...@@ -152,11 +152,11 @@ const struct logtype logtypes[] = {
NULLFIELD}}, NULLFIELD}},
// Note that brtdeq and brtenq don't name the new size or fingerprint. We can calculate them properly. // Note that brtdeq and brtenq don't name the new size or fingerprint. We can calculate them properly.
{"brtdeq", 'U', FA{{"FILENUM", "filenum", 0}, {"brtdeq", 'U', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "childnum", 0}, {"u_int32_t", "childnum", 0},
NULLFIELD}}, NULLFIELD}},
{"brtenq", 'Q', FA{{"FILENUM", "filenum", 0}, {"brtenq", 'Q', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "childnum", 0}, {"u_int32_t", "childnum", 0},
{"TXNID", "xid", 0}, {"TXNID", "xid", 0},
{"u_int32_t", "typ", 0}, {"u_int32_t", "typ", 0},
...@@ -165,13 +165,13 @@ const struct logtype logtypes[] = { ...@@ -165,13 +165,13 @@ const struct logtype logtypes[] = {
NULLFIELD}}, NULLFIELD}},
// {"insertinleaf", 'I', FA{{"TXNID", "txnid", 0}, // {"insertinleaf", 'I', FA{{"TXNID", "txnid", 0},
// {"FILENUM", "filenum", 0}, // {"FILENUM", "filenum", 0},
// {"DISKOFF", "diskoff", 0}, // {"BLOCKNUM", "blocknum", 0},
// {"u_int32_t", "pmaidx", 0}, // {"u_int32_t", "pmaidx", 0},
// {"BYTESTRING", "key", 0}, // {"BYTESTRING", "key", 0},
// {"BYTESTRING", "data", 0}, // {"BYTESTRING", "data", 0},
// NULLFIELD}}, // NULLFIELD}},
// {"replaceleafentry", 'L', FA{{"FILENUM", "filenum", 0}, // {"replaceleafentry", 'L', FA{{"FILENUM", "filenum", 0},
// {"DISKOFF", "diskoff", 0}, // {"BLOCKNUM", "blocknum", 0},
// {"u_int32_t", "pmaidx", 0}, // {"u_int32_t", "pmaidx", 0},
// {"LEAFENTRY", "oldleafentry", 0}, // {"LEAFENTRY", "oldleafentry", 0},
// {"LEAFENTRY", "newleafentry", 0}, // {"LEAFENTRY", "newleafentry", 0},
...@@ -185,17 +185,17 @@ const struct logtype logtypes[] = { ...@@ -185,17 +185,17 @@ const struct logtype logtypes[] = {
{"deqrootentry", 'A', FA{{"FILENUM", "filenum", 0}, {"deqrootentry", 'A', FA{{"FILENUM", "filenum", 0},
NULLFIELD}}, NULLFIELD}},
{"insertleafentry", 'I', FA{{"FILENUM", "filenum", 0}, {"insertleafentry", 'I', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "idx", 0}, {"u_int32_t", "idx", 0},
{"LEAFENTRY", "newleafentry", 0}, {"LEAFENTRY", "newleafentry", 0},
NULLFIELD}}, NULLFIELD}},
{"deleteleafentry", 'D', FA{{"FILENUM", "filenum", 0}, {"deleteleafentry", 'D', FA{{"FILENUM", "filenum", 0},
{"DISKOFF", "diskoff", 0}, {"BLOCKNUM", "blocknum", 0},
{"u_int32_t", "idx", 0}, {"u_int32_t", "idx", 0},
NULLFIELD}}, NULLFIELD}},
{"leafsplit", 's', FA{{"FILENUM", "filenum", 0}, // log the creation of a new node by splitting stuff out of an old node {"leafsplit", 's', FA{{"FILENUM", "filenum", 0}, // log the creation of a new node by splitting stuff out of an old node
{"DISKOFF", "old_diskoff", 0}, {"BLOCKNUM", "old_blocknum", 0},
{"DISKOFF", "new_diskoff", 0}, {"BLOCKNUM", "new_blocknum", 0},
{"u_int32_t", "old_n", 0}, {"u_int32_t", "old_n", 0},
{"u_int32_t", "split_at", 0}, {"u_int32_t", "split_at", 0},
{"u_int32_t", "new_nodesize", 0}, {"u_int32_t", "new_nodesize", 0},
......
...@@ -56,10 +56,17 @@ static inline unsigned long long rbuf_ulonglong (struct rbuf *r) { ...@@ -56,10 +56,17 @@ static inline unsigned long long rbuf_ulonglong (struct rbuf *r) {
return ((unsigned long long)(i0)<<32) | ((unsigned long long)(i1)); return ((unsigned long long)(i0)<<32) | ((unsigned long long)(i1));
} }
static inline signed long long rbuf_longlong (struct rbuf *r) {
return (signed long long)rbuf_ulonglong(r);
}
static inline DISKOFF rbuf_diskoff (struct rbuf *r) { static inline DISKOFF rbuf_diskoff (struct rbuf *r) {
unsigned i0 = rbuf_int(r); return rbuf_ulonglong(r);
unsigned i1 = rbuf_int(r); }
return ((unsigned long long)(i0)<<32) | ((unsigned long long)(i1));
static inline BLOCKNUM rbuf_blocknum (struct rbuf *r) {
BLOCKNUM result = make_blocknum(rbuf_longlong(r));
return result;
} }
static inline void rbuf_TXNID (struct rbuf *r, TXNID *txnid) { static inline void rbuf_TXNID (struct rbuf *r, TXNID *txnid) {
......
This diff is collapsed.
...@@ -25,7 +25,7 @@ static void test_serialize(void) { ...@@ -25,7 +25,7 @@ static void test_serialize(void) {
sn.nodesize = nodesize; sn.nodesize = nodesize;
sn.ever_been_written = 0; sn.ever_been_written = 0;
sn.flags = 0x11223344; sn.flags = 0x11223344;
sn.thisnodename = sn.nodesize*20; sn.thisnodename.b = 20;
sn.disk_lsn.lsn = 789; sn.disk_lsn.lsn = 789;
sn.log_lsn.lsn = 123456; sn.log_lsn.lsn = 123456;
sn.layout_version = BRT_LAYOUT_VERSION; sn.layout_version = BRT_LAYOUT_VERSION;
...@@ -38,8 +38,8 @@ static void test_serialize(void) { ...@@ -38,8 +38,8 @@ static void test_serialize(void) {
MALLOC_N(1, sn.u.n.childkeys); MALLOC_N(1, sn.u.n.childkeys);
sn.u.n.childkeys[0] = kv_pair_malloc(hello_string, 6, 0, 0); sn.u.n.childkeys[0] = kv_pair_malloc(hello_string, 6, 0, 0);
sn.u.n.totalchildkeylens = 6; sn.u.n.totalchildkeylens = 6;
BNC_DISKOFF(&sn, 0) = sn.nodesize*30; BNC_BLOCKNUM(&sn, 0).b = 30;
BNC_DISKOFF(&sn, 1) = sn.nodesize*35; BNC_BLOCKNUM(&sn, 1).b = 35;
BNC_SUBTREE_FINGERPRINT(&sn, 0) = random(); BNC_SUBTREE_FINGERPRINT(&sn, 0) = random();
BNC_SUBTREE_FINGERPRINT(&sn, 1) = random(); BNC_SUBTREE_FINGERPRINT(&sn, 1) = random();
BNC_SUBTREE_LEAFENTRY_ESTIMATE(&sn, 0) = random() + (((long long)random())<<32); BNC_SUBTREE_LEAFENTRY_ESTIMATE(&sn, 0) = random() + (((long long)random())<<32);
...@@ -53,12 +53,13 @@ static void test_serialize(void) { ...@@ -53,12 +53,13 @@ static void test_serialize(void) {
BNC_NBYTESINBUF(&sn, 1) = 1*(BRT_CMD_OVERHEAD+KEY_VALUE_OVERHEAD+2+5); BNC_NBYTESINBUF(&sn, 1) = 1*(BRT_CMD_OVERHEAD+KEY_VALUE_OVERHEAD+2+5);
sn.u.n.n_bytes_in_buffers = 3*(BRT_CMD_OVERHEAD+KEY_VALUE_OVERHEAD+2+5); sn.u.n.n_bytes_in_buffers = 3*(BRT_CMD_OVERHEAD+KEY_VALUE_OVERHEAD+2+5);
toku_serialize_brtnode_to(fd, sn.nodesize*(DISKOFF)20, &sn); assert(r==0); toku_serialize_brtnode_to(fd, make_blocknum(20), &sn); assert(r==0);
r = toku_deserialize_brtnode_from(fd, nodesize*(DISKOFF)20, 0/*pass zero for hash*/, &dn); r = toku_deserialize_brtnode_from(fd, make_blocknum(20), 0/*pass zero for hash*/, &dn, nodesize);
assert(r==0); assert(r==0);
assert(dn->thisnodename==nodesize*20); assert(dn->thisnodename.b==20);
assert(dn->disk_lsn.lsn==123456); assert(dn->disk_lsn.lsn==123456);
assert(dn->layout_version ==BRT_LAYOUT_VERSION); assert(dn->layout_version ==BRT_LAYOUT_VERSION);
assert(dn->height == 1); assert(dn->height == 1);
...@@ -67,8 +68,8 @@ static void test_serialize(void) { ...@@ -67,8 +68,8 @@ static void test_serialize(void) {
assert(strcmp(kv_pair_key(dn->u.n.childkeys[0]), "hello")==0); assert(strcmp(kv_pair_key(dn->u.n.childkeys[0]), "hello")==0);
assert(toku_brtnode_pivot_key_len(dn, dn->u.n.childkeys[0])==6); assert(toku_brtnode_pivot_key_len(dn, dn->u.n.childkeys[0])==6);
assert(dn->u.n.totalchildkeylens==6); assert(dn->u.n.totalchildkeylens==6);
assert(BNC_DISKOFF(dn,0)==nodesize*30); assert(BNC_BLOCKNUM(dn,0).b==30);
assert(BNC_DISKOFF(dn,1)==nodesize*35); assert(BNC_BLOCKNUM(dn,1).b==35);
{ {
int i; int i;
for (i=0; i<2; i++) { for (i=0; i<2; i++) {
......
...@@ -25,24 +25,24 @@ void cachetable_count_pinned_test(int n) { ...@@ -25,24 +25,24 @@ void cachetable_count_pinned_test(int n) {
int i; int i;
for (i=1; i<=n; i++) { for (i=1; i<=n; i++) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0); r = toku_cachetable_put(f1, make_blocknum(i), hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
void *v; void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f1, make_blocknum(i), hi, &v);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
} }
for (i=n; i>0; i--) { for (i=n; i>0; i--) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
if (i-1) assert(toku_cachetable_assert_all_unpinned(ct)); if (i-1) assert(toku_cachetable_assert_all_unpinned(ct));
assert(toku_cachefile_count_pinned(f1, 0) == i-1); assert(toku_cachefile_count_pinned(f1, 0) == i-1);
......
...@@ -33,19 +33,19 @@ void cachetable_debug_test(int n) { ...@@ -33,19 +33,19 @@ void cachetable_debug_test(int n) {
for (i=1; i<=n; i++) { for (i=1; i<=n; i++) {
const int item_size = 1; const int item_size = 1;
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, item_size, flush, fetch, 0); r = toku_cachetable_put(f1, make_blocknum(i), hi, (void *)(long)i, item_size, flush, fetch, 0);
assert(r == 0); assert(r == 0);
void *v; int dirty; long long pinned; long pair_size; void *v; int dirty; long long pinned; long pair_size;
r = toku_cachetable_get_key_state(ct, i, f1, &v, &dirty, &pinned, &pair_size); r = toku_cachetable_get_key_state(ct, make_blocknum(i), f1, &v, &dirty, &pinned, &pair_size);
assert(r == 0); assert(r == 0);
assert(v == (void *)(long)i); assert(v == (void *)(long)i);
assert(dirty == CACHETABLE_DIRTY); assert(dirty == CACHETABLE_DIRTY);
assert(pinned == 1); assert(pinned == 1);
assert(pair_size == item_size); assert(pair_size == item_size);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
toku_cachetable_get_state(ct, &num_entries, &hash_size, &size_current, &size_limit); toku_cachetable_get_state(ct, &num_entries, &hash_size, &size_current, &size_limit);
......
...@@ -31,15 +31,15 @@ void test_cachetable_flush(int n) { ...@@ -31,15 +31,15 @@ void test_cachetable_flush(int n) {
int i; int i;
for (i=0; i<n; i++) { for (i=0; i<n; i++) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0); r = toku_cachetable_put(f1, make_blocknum(i), hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0); assert(r == 0);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
hi = toku_cachetable_hash(f2, i); hi = toku_cachetable_hash(f2, make_blocknum(i));
r = toku_cachetable_put(f2, i, hi, (void *)(long)i, 1, flush, fetch, 0); r = toku_cachetable_put(f2, make_blocknum(i), hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0); assert(r == 0);
r = toku_cachetable_unpin(f2, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f2, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
} }
toku_cachetable_verify(ct); toku_cachetable_verify(ct);
...@@ -48,15 +48,15 @@ void test_cachetable_flush(int n) { ...@@ -48,15 +48,15 @@ void test_cachetable_flush(int n) {
for (i=0; i<n; i++) { for (i=0; i<n; i++) {
u_int32_t hi; u_int32_t hi;
void *v; void *v;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f1, make_blocknum(i), hi, &v);
assert(r == 0 && v == (void *)(long)i); assert(r == 0 && v == (void *)(long)i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
hi = toku_cachetable_hash(f2, i); hi = toku_cachetable_hash(f2, make_blocknum(i));
r = toku_cachetable_maybe_get_and_pin(f2, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f2, make_blocknum(i), hi, &v);
assert(r == 0 && v == (void *)(long)i); assert(r == 0 && v == (void *)(long)i);
r = toku_cachetable_unpin(f2, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f2, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
} }
...@@ -68,13 +68,13 @@ void test_cachetable_flush(int n) { ...@@ -68,13 +68,13 @@ void test_cachetable_flush(int n) {
for (i=0; i<n; i++) { for (i=0; i<n; i++) {
u_int32_t hi; u_int32_t hi;
void *v; void *v;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f1, make_blocknum(i), hi, &v);
assert(r != 0); assert(r != 0);
hi = toku_cachetable_hash(f2, i); hi = toku_cachetable_hash(f2, make_blocknum(i));
r = toku_cachetable_maybe_get_and_pin(f2, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f2, make_blocknum(i), hi, &v);
assert(r == 0); assert(r == 0);
r = toku_cachetable_unpin(f2, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f2, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
} }
......
...@@ -25,41 +25,41 @@ void cachetable_put_test(int n) { ...@@ -25,41 +25,41 @@ void cachetable_put_test(int n) {
int i; int i;
for (i=1; i<=n; i++) { for (i=1; i<=n; i++) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0); r = toku_cachetable_put(f1, make_blocknum(i), hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0); r = toku_cachetable_put(f1, make_blocknum(i), hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == -1); assert(r == -1);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
// the second put returns an error put increments the pin count, so we have // the second put returns an error put increments the pin count, so we have
// to unpin it here // to unpin it here
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
void *v; void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f1, make_blocknum(i), hi, &v);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
} }
for (i=n; i>0; i--) { for (i=n; i>0; i--) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i-1); assert(toku_cachefile_count_pinned(f1, 0) == i-1);
} }
assert(toku_cachefile_count_pinned(f1, 1) == 0); assert(toku_cachefile_count_pinned(f1, 1) == 0);
toku_cachetable_verify(ct); toku_cachetable_verify(ct);
CACHEKEY k = n+1; CACHEKEY k = make_blocknum(n+1);
r = toku_cachetable_unpin(f1, k, toku_cachetable_hash(f1, k), CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, k, toku_cachetable_hash(f1, k), CACHETABLE_CLEAN, 1);
assert(r != 0); assert(r != 0);
......
...@@ -55,10 +55,10 @@ static void r_flush (CACHEFILE f __attribute__((__unused__)), ...@@ -55,10 +55,10 @@ static void r_flush (CACHEFILE f __attribute__((__unused__)),
test_mutex_lock(); test_mutex_lock();
for (i=0; i<n_keys; i++) { for (i=0; i<n_keys; i++) {
if (keys[i]==k) { if (keys[i].b==k.b) {
assert(vals[i]==value); assert(vals[i]==value);
if (!keep_me) { if (!keep_me) {
if (verbose) printf("%s: %d/%d %llx\n", __FUNCTION__, i, n_keys, k); if (verbose) printf("%s: %d/%d %" PRIx64 "\n", __FUNCTION__, i, n_keys, k.b);
keys[i]=keys[n_keys-1]; keys[i]=keys[n_keys-1];
vals[i]=vals[n_keys-1]; vals[i]=vals[n_keys-1];
n_keys--; n_keys--;
...@@ -98,9 +98,9 @@ static void test_rename (void) { ...@@ -98,9 +98,9 @@ static void test_rename (void) {
int ra = random()%3; int ra = random()%3;
if (ra<=1) { if (ra<=1) {
// Insert something // Insert something
CACHEKEY nkey = random(); CACHEKEY nkey = make_blocknum(random());
long nval = random(); long nval = random();
if (verbose) printf("n_keys=%d Insert %08llx\n", n_keys, nkey); if (verbose) printf("n_keys=%d Insert %08" PRIx64 "\n", n_keys, nkey.b);
u_int32_t hnkey = toku_cachetable_hash(f, nkey); u_int32_t hnkey = toku_cachetable_hash(f, nkey);
r = toku_cachetable_put(f, nkey, hnkey, r = toku_cachetable_put(f, nkey, hnkey,
(void*)nval, 1, (void*)nval, 1,
...@@ -122,13 +122,13 @@ static void test_rename (void) { ...@@ -122,13 +122,13 @@ static void test_rename (void) {
} else if (ra==2 && n_keys>0) { } else if (ra==2 && n_keys>0) {
// Rename something // Rename something
int objnum = random()%n_keys; int objnum = random()%n_keys;
CACHEKEY nkey = random(); CACHEKEY nkey = make_blocknum(random());
test_mutex_lock(); test_mutex_lock();
CACHEKEY okey = keys[objnum]; CACHEKEY okey = keys[objnum];
test_mutex_unlock(); test_mutex_unlock();
void *current_value; void *current_value;
long current_size; long current_size;
if (verbose) printf("Rename %llx to %llx\n", okey, nkey); if (verbose) printf("Rename %" PRIx64 " to %" PRIx64 "\n", okey.b, nkey.b);
r = toku_cachetable_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &current_value, &current_size, r_flush, r_fetch, 0); r = toku_cachetable_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &current_value, &current_size, r_flush, r_fetch, 0);
if (r == -42) continue; if (r == -42) continue;
assert(r==0); assert(r==0);
...@@ -139,7 +139,7 @@ static void test_rename (void) { ...@@ -139,7 +139,7 @@ static void test_rename (void) {
// get_and_pin may reorganize the keys[], so we need to find it again // get_and_pin may reorganize the keys[], so we need to find it again
int j; int j;
for (j=0; j < n_keys; j++) for (j=0; j < n_keys; j++)
if (keys[j] == okey) if (keys[j].b == okey.b)
break; break;
assert(j < n_keys); assert(j < n_keys);
keys[j]=nkey; keys[j]=nkey;
...@@ -151,7 +151,7 @@ static void test_rename (void) { ...@@ -151,7 +151,7 @@ static void test_rename (void) {
// test rename fails if old key does not exist in the cachetable // test rename fails if old key does not exist in the cachetable
CACHEKEY okey, nkey; CACHEKEY okey, nkey;
while (1) { while (1) {
okey = random(); okey = make_blocknum(random());
void *v; void *v;
r = toku_cachetable_maybe_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &v); r = toku_cachetable_maybe_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &v);
if (r != 0) if (r != 0)
...@@ -159,7 +159,7 @@ static void test_rename (void) { ...@@ -159,7 +159,7 @@ static void test_rename (void) {
r = toku_cachetable_unpin(f, okey, toku_cachetable_hash(f, okey), CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f, okey, toku_cachetable_hash(f, okey), CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
} }
nkey = random(); nkey = make_blocknum(random());
r = toku_cachetable_rename(f, okey, nkey); r = toku_cachetable_rename(f, okey, nkey);
assert(r != 0); assert(r != 0);
......
...@@ -26,7 +26,7 @@ static void f_flush (CACHEFILE f, ...@@ -26,7 +26,7 @@ static void f_flush (CACHEFILE f,
BOOL rename_p __attribute__((__unused__))) { BOOL rename_p __attribute__((__unused__))) {
assert(size==BLOCKSIZE); assert(size==BLOCKSIZE);
if (write_me) { if (write_me) {
int r = pwrite(toku_cachefile_fd(f), value, BLOCKSIZE, key); int r = pwrite(toku_cachefile_fd(f), value, BLOCKSIZE, key.b);
assert(r==BLOCKSIZE); assert(r==BLOCKSIZE);
} }
if (!keep_me) { if (!keep_me) {
...@@ -42,7 +42,7 @@ static int f_fetch (CACHEFILE f, ...@@ -42,7 +42,7 @@ static int f_fetch (CACHEFILE f,
void*extraargs __attribute__((__unused__)), void*extraargs __attribute__((__unused__)),
LSN *modified_lsn __attribute__((__unused__))) { LSN *modified_lsn __attribute__((__unused__))) {
void *buf = malloc(BLOCKSIZE); void *buf = malloc(BLOCKSIZE);
int r = pread(toku_cachefile_fd(f), buf, BLOCKSIZE, key); int r = pread(toku_cachefile_fd(f), buf, BLOCKSIZE, key.b);
assert(r==BLOCKSIZE); assert(r==BLOCKSIZE);
*value = buf; *value = buf;
*sizep = BLOCKSIZE; *sizep = BLOCKSIZE;
...@@ -66,7 +66,7 @@ static void writeit (void) { ...@@ -66,7 +66,7 @@ static void writeit (void) {
int i, r; int i, r;
for (i=0; i<N; i++) { for (i=0; i<N; i++) {
void *buf = malloc(BLOCKSIZE); void *buf = malloc(BLOCKSIZE);
CACHEKEY key = i*BLOCKSIZE; CACHEKEY key = make_blocknum(i*BLOCKSIZE);
u_int32_t fullhash = toku_cachetable_hash(f, key); u_int32_t fullhash = toku_cachetable_hash(f, key);
int j; int j;
for (j=0; j<BLOCKSIZE; j++) ((char*)buf)[j]=(i+j)%256; for (j=0; j<BLOCKSIZE; j++) ((char*)buf)[j]=(i+j)%256;
...@@ -86,9 +86,8 @@ static void readit (void) { ...@@ -86,9 +86,8 @@ static void readit (void) {
int i, r; int i, r;
void *block; void *block;
long current_size; long current_size;
CACHEKEY key;
for (i=0; i<N; i++) { for (i=0; i<N; i++) {
key = i*BLOCKSIZE; CACHEKEY key = make_blocknum(i*BLOCKSIZE);
u_int32_t fullhash = toku_cachetable_hash(f, key); u_int32_t fullhash = toku_cachetable_hash(f, key);
r=toku_cachetable_get_and_pin(f, key, fullhash, &block, &current_size, f_flush, f_fetch, 0); assert(r==0); r=toku_cachetable_get_and_pin(f, key, fullhash, &block, &current_size, f_flush, f_fetch, 0); assert(r==0);
r=toku_cachetable_unpin(f, key, fullhash, 0, BLOCKSIZE); assert(r==0); r=toku_cachetable_unpin(f, key, fullhash, 0, BLOCKSIZE); assert(r==0);
......
This diff is collapsed.
/* -*- mode: C; c-basic-offset: 4 -*- */ /* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved." #ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
#include "memory.h" #include <inttypes.h>
#include "cachetable.h"
#include "toku_assert.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include "memory.h"
#include "cachetable.h"
#include "toku_assert.h"
#include "test.h" #include "test.h"
// this mutex is used by some of the tests to serialize access to some // this mutex is used by some of the tests to serialize access to some
...@@ -51,7 +52,7 @@ static void print_ints(void) { ...@@ -51,7 +52,7 @@ static void print_ints(void) {
int i; int i;
for (i=0; i<n_present; i++) { for (i=0; i<n_present; i++) {
if (i==0) printf("{"); else printf(","); if (i==0) printf("{"); else printf(",");
printf("{%lld,%p}", present_items[i].key, present_items[i].cf); printf("{%" PRId64 ",%p}", present_items[i].key.b, present_items[i].cf);
} }
printf("}\n"); printf("}\n");
} }
...@@ -72,7 +73,7 @@ static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) { ...@@ -72,7 +73,7 @@ static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) {
test_mutex_lock(); test_mutex_lock();
assert(n_present<=N_PRESENT_LIMIT); assert(n_present<=N_PRESENT_LIMIT);
for (i=0; i<n_present; i++) { for (i=0; i<n_present; i++) {
if (present_items[i].cf==cf && present_items[i].key==key) { if (present_items[i].cf==cf && present_items[i].key.b==key.b) {
present_items[i]=present_items[n_present-1]; present_items[i]=present_items[n_present-1];
n_present--; n_present--;
test_mutex_unlock(); test_mutex_unlock();
...@@ -80,7 +81,7 @@ static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) { ...@@ -80,7 +81,7 @@ static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) {
return; return;
} }
} }
printf("Whoops, %p,%lld was already not present\n", cf ,key); printf("Whoops, %p,%" PRId64 " was already not present\n", cf ,key.b);
abort(); abort();
test_mutex_unlock(); test_mutex_unlock();
} }
...@@ -107,15 +108,15 @@ static void flush_forchain (CACHEFILE f __attribute__((__unused__)), ...@@ -107,15 +108,15 @@ static void flush_forchain (CACHEFILE f __attribute__((__unused__)),
int *v = value; int *v = value;
//toku_cachetable_print_state(ct); //toku_cachetable_print_state(ct);
//printf("Flush %lld %d\n", key, (int)value); //printf("Flush %lld %d\n", key, (int)value);
assert((long)v==(long)key); assert((long)v==(long)key.b);
item_becomes_not_present(f, key); item_becomes_not_present(f, key);
//print_ints(); //print_ints();
} }
static int fetch_forchain (CACHEFILE f, CACHEKEY key, u_int32_t fullhash, void**value, long *sizep __attribute__((__unused__)), void*extraargs, LSN *written_lsn) { static int fetch_forchain (CACHEFILE f, CACHEKEY key, u_int32_t fullhash, void**value, long *sizep __attribute__((__unused__)), void*extraargs, LSN *written_lsn) {
assert(toku_cachetable_hash(f, key)==fullhash); assert(toku_cachetable_hash(f, key)==fullhash);
assert((long)extraargs==(long)key); assert((long)extraargs==(long)key.b);
*value = (void*)(long)key; *value = (void*)(long)key.b;
written_lsn->lsn = 0; written_lsn->lsn = 0;
return 0; return 0;
} }
...@@ -162,11 +163,11 @@ static void test_chaining (void) { ...@@ -162,11 +163,11 @@ static void test_chaining (void) {
for (i=0; i<N_PRESENT_LIMIT; i++) { for (i=0; i<N_PRESENT_LIMIT; i++) {
int fnum = i%N_FILES; int fnum = i%N_FILES;
//printf("%s:%d Add %d\n", __FILE__, __LINE__, i); //printf("%s:%d Add %d\n", __FILE__, __LINE__, i);
u_int32_t fhash = toku_cachetable_hash(f[fnum], i); u_int32_t fhash = toku_cachetable_hash(f[fnum], make_blocknum(i));
r = toku_cachetable_put(f[fnum], i, fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i); r = toku_cachetable_put(f[fnum], make_blocknum(i), fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i);
assert(r==0); assert(r==0);
item_becomes_present(f[fnum], i); item_becomes_present(f[fnum], make_blocknum(i));
r = toku_cachetable_unpin(f[fnum], i, fhash, CACHETABLE_CLEAN, test_object_size); r = toku_cachetable_unpin(f[fnum], make_blocknum(i), fhash, CACHETABLE_CLEAN, test_object_size);
assert(r==0); assert(r==0);
//print_ints(); //print_ints();
} }
...@@ -189,7 +190,7 @@ static void test_chaining (void) { ...@@ -189,7 +190,7 @@ static void test_chaining (void) {
NULL, NULL,
flush_forchain, flush_forchain,
fetch_forchain, fetch_forchain,
(void*)(long)whichkey (void*)(long)whichkey.b
); );
assert(r==0); assert(r==0);
r = toku_cachetable_unpin(whichcf, r = toku_cachetable_unpin(whichcf,
...@@ -204,18 +205,19 @@ static void test_chaining (void) { ...@@ -204,18 +205,19 @@ static void test_chaining (void) {
// i is always incrementing, so we need not worry about inserting a duplicate // i is always incrementing, so we need not worry about inserting a duplicate
// if i is a duplicate, cachetable_put will return -1 // if i is a duplicate, cachetable_put will return -1
// printf("%s:%d Add {%ld,%p}\n", __FILE__, __LINE__, i, f[fnum]); // printf("%s:%d Add {%ld,%p}\n", __FILE__, __LINE__, i, f[fnum]);
u_int32_t fhash = toku_cachetable_hash(f[fnum], i); u_int32_t fhash = toku_cachetable_hash(f[fnum], make_blocknum(i));
r = toku_cachetable_put(f[fnum], i, fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i); r = toku_cachetable_put(f[fnum], make_blocknum(i), fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i);
assert(r==0 || r==-1); assert(r==0 || r==-1);
if (r==0) { if (r==0) {
item_becomes_present(f[fnum], i); item_becomes_present(f[fnum], make_blocknum(i));
//print_ints(); //print_ints();
//cachetable_print_state(ct); //cachetable_print_state(ct);
} }
r = toku_cachetable_unpin(f[fnum], i, fhash, CACHETABLE_CLEAN, test_object_size); r = toku_cachetable_unpin(f[fnum], make_blocknum(i), fhash, CACHETABLE_CLEAN, test_object_size);
assert(r==0); assert(r==0);
long long pinned; long long pinned;
r = toku_cachetable_get_key_state(ct, i, f[fnum], 0, 0, &pinned, 0); r = toku_cachetable_get_key_state(ct, make_blocknum(i), f[fnum], 0, 0, &pinned, 0);
assert(r==0); assert(r==0);
assert(pinned == 0); assert(pinned == 0);
verify_cachetable_against_present(); verify_cachetable_against_present();
......
...@@ -25,31 +25,31 @@ void cachetable_unpin_test(int n) { ...@@ -25,31 +25,31 @@ void cachetable_unpin_test(int n) {
int i; int i;
for (i=1; i<=n; i++) { for (i=1; i<=n; i++) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0); r = toku_cachetable_put(f1, make_blocknum(i), hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
void *v; void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v); r = toku_cachetable_maybe_get_and_pin(f1, make_blocknum(i), hi, &v);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i); assert(toku_cachefile_count_pinned(f1, 0) == i);
} }
for (i=n; i>0; i--) { for (i=n; i>0; i--) {
u_int32_t hi; u_int32_t hi;
hi = toku_cachetable_hash(f1, i); hi = toku_cachetable_hash(f1, make_blocknum(i));
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, make_blocknum(i), hi, CACHETABLE_CLEAN, 1);
assert(r == 0); assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i-1); assert(toku_cachefile_count_pinned(f1, 0) == i-1);
} }
assert(toku_cachefile_count_pinned(f1, 1) == 0); assert(toku_cachefile_count_pinned(f1, 1) == 0);
toku_cachetable_verify(ct); toku_cachetable_verify(ct);
CACHEKEY k = n+1; CACHEKEY k = make_blocknum(n+1);
r = toku_cachetable_unpin(f1, k, toku_cachetable_hash(f1, k), CACHETABLE_CLEAN, 1); r = toku_cachetable_unpin(f1, k, toku_cachetable_hash(f1, k), CACHETABLE_CLEAN, 1);
assert(r != 0); assert(r != 0);
......
...@@ -22,7 +22,7 @@ int fnamelen; ...@@ -22,7 +22,7 @@ int fnamelen;
char *fname; char *fname;
void doit (void) { void doit (void) {
DISKOFF nodea,nodeb; BLOCKNUM nodea,nodeb;
u_int32_t fingerprinta=0; u_int32_t fingerprinta=0;
int r; int r;
......
...@@ -48,7 +48,7 @@ int fnamelen; ...@@ -48,7 +48,7 @@ int fnamelen;
char *fname; char *fname;
void doit (int ksize __attribute__((__unused__))) { void doit (int ksize __attribute__((__unused__))) {
DISKOFF cnodes[BRT_FANOUT], bnode, anode; BLOCKNUM cnodes[BRT_FANOUT], bnode, anode;
u_int32_t fingerprints[BRT_FANOUT]; u_int32_t fingerprints[BRT_FANOUT];
char *keys[BRT_FANOUT-1]; char *keys[BRT_FANOUT-1];
......
...@@ -98,6 +98,11 @@ static inline void wbuf_u_int32_t (struct wbuf *w, u_int32_t v) { ...@@ -98,6 +98,11 @@ static inline void wbuf_u_int32_t (struct wbuf *w, u_int32_t v) {
static inline void wbuf_DISKOFF (struct wbuf *w, DISKOFF off) { static inline void wbuf_DISKOFF (struct wbuf *w, DISKOFF off) {
wbuf_ulonglong(w, (u_int64_t)off); wbuf_ulonglong(w, (u_int64_t)off);
} }
static inline void wbuf_BLOCKNUM (struct wbuf *w, BLOCKNUM b) {
wbuf_ulonglong(w, b.b);
}
static inline void wbuf_TXNID (struct wbuf *w, TXNID tid) { static inline void wbuf_TXNID (struct wbuf *w, TXNID tid) {
wbuf_ulonglong(w, tid); wbuf_ulonglong(w, tid);
...@@ -115,15 +120,15 @@ static inline void wbuf_LOGGEDBRTHEADER (struct wbuf *w, LOGGEDBRTHEADER h) { ...@@ -115,15 +120,15 @@ static inline void wbuf_LOGGEDBRTHEADER (struct wbuf *w, LOGGEDBRTHEADER h) {
wbuf_uint(w, h.size); wbuf_uint(w, h.size);
wbuf_uint(w, h.flags); wbuf_uint(w, h.flags);
wbuf_uint(w, h.nodesize); wbuf_uint(w, h.nodesize);
wbuf_DISKOFF(w, h.freelist); wbuf_BLOCKNUM(w, h.free_blocks);
wbuf_DISKOFF(w, h.unused_memory); wbuf_BLOCKNUM(w, h.unused_blocks);
wbuf_int(w, h.n_named_roots); wbuf_int(w, h.n_named_roots);
if ((signed)h.n_named_roots==-1) { if ((signed)h.n_named_roots==-1) {
wbuf_DISKOFF(w, h.u.one.root); wbuf_BLOCKNUM(w, h.u.one.root);
} else { } else {
int i; int i;
for (i=0; i<h.n_named_roots; i++) { for (i=0; i<h.n_named_roots; i++) {
wbuf_DISKOFF(w, h.u.many.roots[i]); wbuf_BLOCKNUM(w, h.u.many.roots[i]);
wbuf_bytes (w, h.u.many.names[i], (u_int32_t)(1+strlen(h.u.many.names[i]))); wbuf_bytes (w, h.u.many.names[i], (u_int32_t)(1+strlen(h.u.many.names[i])));
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment