Moved the "btree" test from befs/ to bfs/.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4899 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
SubDir OBOS_TOP src tests add-ons kernel file_systems befs ;
|
SubDir OBOS_TOP src tests add-ons kernel file_systems befs ;
|
||||||
|
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs array ;
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs array ;
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs btree ;
|
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs queries ;
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs queries ;
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs randomread ;
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs randomread ;
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs rename ;
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems befs rename ;
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ SubDir OBOS_TOP src tests add-ons kernel file_systems bfs ;
|
|||||||
#SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs blockAllocator ;
|
#SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs blockAllocator ;
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs bufferPool ;
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs bufferPool ;
|
||||||
SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs bfs_shell ;
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs bfs_shell ;
|
||||||
|
SubInclude OBOS_TOP src tests add-ons kernel file_systems bfs btree ;
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/* Inode - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Inode.h"
|
||||||
|
#include "Volume.h"
|
||||||
|
#include "Journal.h"
|
||||||
|
|
||||||
|
|
||||||
|
Inode::Inode(const char *name,int32 mode)
|
||||||
|
:
|
||||||
|
fMode(mode)
|
||||||
|
{
|
||||||
|
fFile.SetTo(name,B_CREATE_FILE | B_READ_WRITE | B_ERASE_FILE);
|
||||||
|
fSize = 0;
|
||||||
|
fVolume = new Volume(&fFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Inode::~Inode()
|
||||||
|
{
|
||||||
|
delete fVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||||
|
{
|
||||||
|
// the whole file data is covered by this one block_run structure...
|
||||||
|
run.SetTo(0,0,1);
|
||||||
|
offset = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::Append(Transaction *transaction, off_t bytes)
|
||||||
|
{
|
||||||
|
return SetFileSize(transaction,Size() + bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::SetFileSize(Transaction *, off_t bytes)
|
||||||
|
{
|
||||||
|
//printf("set size = %ld\n",bytes);
|
||||||
|
fSize = bytes;
|
||||||
|
return fFile.SetSize(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef INODE_H
|
||||||
|
#define INODE_H
|
||||||
|
/* Inode - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
#include <File.h>
|
||||||
|
|
||||||
|
#include "Lock.h"
|
||||||
|
#include "bfs.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Volume;
|
||||||
|
class Transaction;
|
||||||
|
|
||||||
|
|
||||||
|
class Inode {
|
||||||
|
public:
|
||||||
|
Inode(const char *name,int32 mode = S_STR_INDEX | S_ALLOW_DUPS);
|
||||||
|
~Inode();
|
||||||
|
|
||||||
|
ReadWriteLock &Lock() { return fLock; }
|
||||||
|
|
||||||
|
status_t FindBlockRun(off_t pos,block_run &run,off_t &offset);
|
||||||
|
status_t Append(Transaction *,off_t bytes);
|
||||||
|
status_t SetFileSize(Transaction *,off_t bytes);
|
||||||
|
|
||||||
|
Volume *GetVolume() const { return fVolume; }
|
||||||
|
off_t ID() const { return 0; }
|
||||||
|
int32 Mode() const { return fMode; }
|
||||||
|
char *Name() const { return "whatever"; }
|
||||||
|
block_run BlockRun() const { return block_run::Run(0,0,0); }
|
||||||
|
block_run Parent() const { return block_run::Run(0,0,0); }
|
||||||
|
off_t BlockNumber() const { return 0; }
|
||||||
|
bfs_inode *Node() { return (bfs_inode *)1; }
|
||||||
|
|
||||||
|
off_t Size() const { return fSize; }
|
||||||
|
bool IsContainer() const { return true; }
|
||||||
|
bool IsDirectory() const { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Volume *fVolume;
|
||||||
|
BFile fFile;
|
||||||
|
off_t fSize;
|
||||||
|
ReadWriteLock fLock;
|
||||||
|
int32 fMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* INODE_H */
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
SubDir OBOS_TOP src tests add-ons kernel file_systems befs btree ;
|
||||||
|
|
||||||
|
SubDirHdrs $(OBOS_TOP) src add-ons kernel file_systems bfs ;
|
||||||
|
|
||||||
|
rule FPreIncludes { return -include\ $(1:D=$(SUBDIR)) ; }
|
||||||
|
|
||||||
|
{
|
||||||
|
local defines = [ FDefines USER DEBUG ] ; # _NO_INLINE_ASM
|
||||||
|
local preIncludes = [ FPreIncludes Journal.h Inode.h ] ;
|
||||||
|
SubDirC++Flags $(defines) $(preIncludes) -fno-exceptions -fno-rtti ; #-fcheck-memory-usage
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest btreeTest
|
||||||
|
: test.cpp
|
||||||
|
Volume.cpp
|
||||||
|
Inode.cpp
|
||||||
|
cache.cpp
|
||||||
|
BPlusTree.cpp
|
||||||
|
Utility.cpp
|
||||||
|
Debug.cpp
|
||||||
|
: be ;
|
||||||
|
|
||||||
|
# Tell Jam where to find these sources
|
||||||
|
SEARCH on [ FGristFiles BPlusTree.cpp Utility.cpp Debug.cpp ]
|
||||||
|
= [ FDirName $(OBOS_TOP) src add-ons kernel file_systems bfs ] ;
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef JOURNAL_H
|
||||||
|
#define JOURNAL_H
|
||||||
|
/* Journal - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "Volume.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Transaction {
|
||||||
|
public:
|
||||||
|
Transaction(Volume *volume,off_t refBlock)
|
||||||
|
:
|
||||||
|
fVolume(volume)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Transaction()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t WriteBlocks(off_t blockNumber,const uint8 *buffer,size_t numBlocks = 1)
|
||||||
|
{
|
||||||
|
return cached_write(fVolume->Device(),blockNumber,buffer,numBlocks,fVolume->BlockSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Done()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Volume *fVolume;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JOURNAL_H */
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/* Volume - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Volume.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::Panic()
|
||||||
|
{
|
||||||
|
printf("PANIC!\n");
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef VOLUME_H
|
||||||
|
#define VOLUME_H
|
||||||
|
/* Volume - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include "Lock.h"
|
||||||
|
#include "bfs.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BFile;
|
||||||
|
|
||||||
|
|
||||||
|
class Volume {
|
||||||
|
public:
|
||||||
|
Volume(BFile *file) : fFile(file) {}
|
||||||
|
|
||||||
|
BFile *Device() { return fFile; }
|
||||||
|
|
||||||
|
int32 BlockSize() const { return 1024; }
|
||||||
|
off_t ToBlock(block_run run) const { return run.start; }
|
||||||
|
block_run ToBlockRun(off_t block) const { return block_run::Run(0,0,block); }
|
||||||
|
|
||||||
|
static void Panic();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BFile *fFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* VOLUME_H */
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/* cache - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
|
#include <File.h>
|
||||||
|
#include <List.h>
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* A note from the author: this cache implementation can only be used
|
||||||
|
* with the test program, it really suites no other needs.
|
||||||
|
* It's very simple and not that efficient, and simple holds the whole
|
||||||
|
* file in memory, all the time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
BList gBlocks;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
init_cache(BFile */*file*/,int32 /*blockSize*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
shutdown_cache(BFile *file,int32 blockSize)
|
||||||
|
{
|
||||||
|
for (int32 i = 0;i < gBlocks.CountItems();i++) {
|
||||||
|
void *buffer = gBlocks.ItemAt(i);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
printf("cache is corrupt!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
file->WriteAt(i * blockSize,buffer,blockSize);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
readBlocks(BFile *file,uint32 num,uint32 size)
|
||||||
|
{
|
||||||
|
for (int32 i = gBlocks.CountItems();i <= num;i++) {
|
||||||
|
void *buffer = malloc(size);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
gBlocks.AddItem(buffer);
|
||||||
|
if (file->ReadAt(i * size,buffer,size) < B_OK)
|
||||||
|
return B_IO_ERROR;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
cached_write(BFile *file, off_t num,const void *data,off_t numBlocks, int blockSize)
|
||||||
|
{
|
||||||
|
//printf("cached_write(num = %Ld,data = %p,numBlocks = %Ld,blockSize = %ld)\n",num,data,numBlocks,blockSize);
|
||||||
|
if (file == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (num >= gBlocks.CountItems())
|
||||||
|
puts("Oh no!");
|
||||||
|
|
||||||
|
void *buffer = gBlocks.ItemAt(num);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (buffer != data && numBlocks == 1)
|
||||||
|
memcpy(buffer,data,blockSize);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
get_block(BFile *file, off_t num, int blockSize)
|
||||||
|
{
|
||||||
|
//printf("get_block(num = %Ld,blockSize = %ld)\n",num,blockSize);
|
||||||
|
if (file == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (num >= gBlocks.CountItems())
|
||||||
|
readBlocks(file,num,blockSize);
|
||||||
|
|
||||||
|
return gBlocks.ItemAt(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
release_block(BFile *file, off_t num)
|
||||||
|
{
|
||||||
|
//printf("release_block(num = %Ld)\n",num);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef CACHE_H
|
||||||
|
#define CACHE_H
|
||||||
|
/* cache - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, [email protected]
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
class BFile;
|
||||||
|
|
||||||
|
|
||||||
|
extern void init_cache(BFile *file, int32 blockSize);
|
||||||
|
extern void shutdown_cache(BFile *file, int32 blockSize);
|
||||||
|
|
||||||
|
extern int cached_write(BFile *file, off_t bnum, const void *data,off_t num_blocks, int bsize);
|
||||||
|
extern void *get_block(BFile *file, off_t bnum, int bsize);
|
||||||
|
extern int release_block(BFile *file, off_t bnum);
|
||||||
|
|
||||||
|
#endif /* CACHE_H */
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/* cpp - emulation for the B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
@@ -0,0 +1,759 @@
|
|||||||
|
/* test - BFS B+Tree torture test
|
||||||
|
**
|
||||||
|
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||||
|
** This file may be used under the terms of the OpenBeOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Volume.h"
|
||||||
|
#include "Inode.h"
|
||||||
|
#include "BPlusTree.h"
|
||||||
|
|
||||||
|
#include <List.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_ITERATIONS 10
|
||||||
|
#define DEFAULT_NUM_KEYS 100
|
||||||
|
#define DEFAULT_KEY_TYPE S_STR_INDEX
|
||||||
|
|
||||||
|
#define MIN_STRING 3
|
||||||
|
#define MAX_STRING 256
|
||||||
|
|
||||||
|
struct key {
|
||||||
|
void *data;
|
||||||
|
uint32 length;
|
||||||
|
int32 in;
|
||||||
|
int32 count;
|
||||||
|
off_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
key *gKeys;
|
||||||
|
int32 gNum = DEFAULT_NUM_KEYS;
|
||||||
|
int32 gType = DEFAULT_KEY_TYPE;
|
||||||
|
int32 gTreeCount = 0;
|
||||||
|
bool gVerbose, gExcessive;
|
||||||
|
int32 gIterations = DEFAULT_ITERATIONS;
|
||||||
|
int32 gHard = 1;
|
||||||
|
Volume *gVolume;
|
||||||
|
int32 gSeed = 42;
|
||||||
|
|
||||||
|
// from cache.cpp (yes, we are that mean)
|
||||||
|
extern BList gBlocks;
|
||||||
|
|
||||||
|
|
||||||
|
// prototypes
|
||||||
|
void bailOut();
|
||||||
|
void bailOutWithKey(void *key, uint16 length);
|
||||||
|
void dumpTree();
|
||||||
|
void dumpKey(void *key, int32 length);
|
||||||
|
void dumpKeys();
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dumpTree()
|
||||||
|
{
|
||||||
|
puts("\n*** Tree-Dump:\n");
|
||||||
|
|
||||||
|
bplustree_header *header = (bplustree_header *)gBlocks.ItemAt(0);
|
||||||
|
dump_bplustree_header(header);
|
||||||
|
|
||||||
|
for (int32 i = 1;i < gBlocks.CountItems();i++) {
|
||||||
|
bplustree_node *node = (bplustree_node *)gBlocks.ItemAt(i);
|
||||||
|
printf("\n--- %s node at %ld --------------------------------------\n",
|
||||||
|
node->overflow_link == BPLUSTREE_NULL ? "leaf" : "index",
|
||||||
|
i * BPLUSTREE_NODE_SIZE);
|
||||||
|
dump_bplustree_node(node,header,gVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
bailOut()
|
||||||
|
{
|
||||||
|
if (gVerbose) {
|
||||||
|
// dump the tree
|
||||||
|
dumpTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
// in any case, write the tree back to disk
|
||||||
|
shutdown_cache(gVolume->Device(),gVolume->BlockSize());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
bailOutWithKey(void *key,uint16 length)
|
||||||
|
{
|
||||||
|
dumpKey(key,length);
|
||||||
|
putchar('\n');
|
||||||
|
bailOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dumpKey(void *key,int32 length)
|
||||||
|
{
|
||||||
|
switch (gType) {
|
||||||
|
case S_STR_INDEX:
|
||||||
|
printf("\"%s\" (%ld bytes)",key,length);
|
||||||
|
break;
|
||||||
|
case S_INT_INDEX:
|
||||||
|
printf("%ld",*(int32 *)key);
|
||||||
|
break;
|
||||||
|
case S_UINT_INDEX:
|
||||||
|
printf("%lu",*(uint32 *)key);
|
||||||
|
break;
|
||||||
|
case S_LONG_LONG_INDEX:
|
||||||
|
printf("%Ld",*(int64 *)key);
|
||||||
|
break;
|
||||||
|
case S_ULONG_LONG_INDEX:
|
||||||
|
printf("%Lu",*(uint64 *)key);
|
||||||
|
break;
|
||||||
|
case S_FLOAT_INDEX:
|
||||||
|
printf("%g",*(float *)key);
|
||||||
|
break;
|
||||||
|
case S_DOUBLE_INDEX:
|
||||||
|
printf("%g",*(double *)key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((gType == S_INT_INDEX || gType == S_UINT_INDEX || gType == S_FLOAT_INDEX)
|
||||||
|
&& length != 4)
|
||||||
|
printf(" (wrong length %ld)",length);
|
||||||
|
else if ((gType == S_LONG_LONG_INDEX || gType == S_ULONG_LONG_INDEX || gType == S_DOUBLE_INDEX)
|
||||||
|
&& length != 8)
|
||||||
|
printf(" (wrong length %ld)",length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dumpKeys()
|
||||||
|
{
|
||||||
|
char *type;
|
||||||
|
switch (gType) {
|
||||||
|
case S_STR_INDEX:
|
||||||
|
type = "string";
|
||||||
|
break;
|
||||||
|
case S_INT_INDEX:
|
||||||
|
type = "int32";
|
||||||
|
break;
|
||||||
|
case S_UINT_INDEX:
|
||||||
|
type = "uint32";
|
||||||
|
break;
|
||||||
|
case S_LONG_LONG_INDEX:
|
||||||
|
type = "int64";
|
||||||
|
break;
|
||||||
|
case S_ULONG_LONG_INDEX:
|
||||||
|
type = "uint64";
|
||||||
|
break;
|
||||||
|
case S_FLOAT_INDEX:
|
||||||
|
type = "float";
|
||||||
|
break;
|
||||||
|
case S_DOUBLE_INDEX:
|
||||||
|
type = "double";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("Dumping %ld keys of type %s\n",gNum,type);
|
||||||
|
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
printf("% 8ld. (%3ld) key = ",i,gKeys[i].in);
|
||||||
|
dumpKey(gKeys[i].data,gKeys[i].length);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
//
|
||||||
|
// Functions to generate the keys in every available type
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
generateName(int32 i,char *name,int32 *_length)
|
||||||
|
{
|
||||||
|
// We're using the index position as a hint for the length
|
||||||
|
// of the string - this way, it's much less expansive to
|
||||||
|
// test for string uniqueness.
|
||||||
|
// We don't want to sort the strings to have more realistic
|
||||||
|
// access patterns to the tree (only true for the strings test).
|
||||||
|
int32 length = i % (MAX_STRING - MIN_STRING) + MIN_STRING;
|
||||||
|
for (int32 i = 0;i < length;i++) {
|
||||||
|
int32 c = int32(52.0 * rand() / RAND_MAX);
|
||||||
|
if (c >= 26)
|
||||||
|
name[i] = 'A' + c - 26;
|
||||||
|
else
|
||||||
|
name[i] = 'a' + c;
|
||||||
|
}
|
||||||
|
name[length] = 0;
|
||||||
|
*_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
fillBuffer(void *buffer,int32 start)
|
||||||
|
{
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
switch (gType) {
|
||||||
|
case S_INT_INDEX:
|
||||||
|
{
|
||||||
|
int32 *array = (int32 *)buffer;
|
||||||
|
array[i] = start + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case S_UINT_INDEX:
|
||||||
|
{
|
||||||
|
uint32 *array = (uint32 *)buffer;
|
||||||
|
array[i] = start + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case S_LONG_LONG_INDEX:
|
||||||
|
{
|
||||||
|
int64 *array = (int64 *)buffer;
|
||||||
|
array[i] = start + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case S_ULONG_LONG_INDEX:
|
||||||
|
{
|
||||||
|
uint64 *array = (uint64 *)buffer;
|
||||||
|
array[i] = start + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case S_FLOAT_INDEX:
|
||||||
|
{
|
||||||
|
float *array = (float *)buffer;
|
||||||
|
array[i] = start + i * 1.0001;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case S_DOUBLE_INDEX:
|
||||||
|
{
|
||||||
|
double *array = (double *)buffer;
|
||||||
|
array[i] = start + i * 1.0001;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gKeys[i].value = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
findKey(void *key,int32 length,int32 maxIndex)
|
||||||
|
{
|
||||||
|
for (int32 i = length;i < maxIndex;i += MAX_STRING - MIN_STRING) {
|
||||||
|
if (length == gKeys[i].length
|
||||||
|
&& !memcpy(key,gKeys[i].data,length))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
createKeys()
|
||||||
|
{
|
||||||
|
gKeys = (key *)malloc(gNum * sizeof(key));
|
||||||
|
if (gKeys == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (gType == S_STR_INDEX) {
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
char name[B_FILE_NAME_LENGTH];
|
||||||
|
int32 length,tries = 0;
|
||||||
|
bool last;
|
||||||
|
|
||||||
|
// create unique keys!
|
||||||
|
do {
|
||||||
|
generateName(i,name,&length);
|
||||||
|
} while ((last = findKey(name,length,i)) && tries++ < 100);
|
||||||
|
|
||||||
|
if (last) {
|
||||||
|
printf("Couldn't create unique key list!\n");
|
||||||
|
dumpKeys();
|
||||||
|
bailOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
gKeys[i].data = malloc(length + 1);
|
||||||
|
memcpy(gKeys[i].data,name,length + 1);
|
||||||
|
gKeys[i].length = length;
|
||||||
|
gKeys[i].in = 0;
|
||||||
|
gKeys[i].count = 0;
|
||||||
|
gKeys[i].value = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int32 length;
|
||||||
|
int32 start = 0;
|
||||||
|
switch (gType) {
|
||||||
|
case S_FLOAT_INDEX:
|
||||||
|
case S_INT_INDEX:
|
||||||
|
start = -gNum / 2;
|
||||||
|
case S_UINT_INDEX:
|
||||||
|
length = 4;
|
||||||
|
break;
|
||||||
|
case S_DOUBLE_INDEX:
|
||||||
|
case S_LONG_LONG_INDEX:
|
||||||
|
start = -gNum / 2;
|
||||||
|
case S_ULONG_LONG_INDEX:
|
||||||
|
length = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
uint8 *buffer = (uint8 *)malloc(length * gNum);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
gKeys[i].data = (void *)(buffer + i * length);
|
||||||
|
gKeys[i].length = length;
|
||||||
|
gKeys[i].in = 0;
|
||||||
|
gKeys[i].count = 0;
|
||||||
|
}
|
||||||
|
fillBuffer(buffer,start);
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
//
|
||||||
|
// Tree validity checker
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
checkTreeContents(BPlusTree *tree)
|
||||||
|
{
|
||||||
|
// reset counter
|
||||||
|
for (int32 i = 0;i < gNum;i++)
|
||||||
|
gKeys[i].count = 0;
|
||||||
|
|
||||||
|
TreeIterator iterator(tree);
|
||||||
|
char key[B_FILE_NAME_LENGTH];
|
||||||
|
uint16 length,duplicate;
|
||||||
|
off_t value;
|
||||||
|
status_t status;
|
||||||
|
while ((status = iterator.GetNextEntry(key,&length,B_FILE_NAME_LENGTH,&value,&duplicate)) == B_OK) {
|
||||||
|
if (value < 0 || value >= gNum) {
|
||||||
|
iterator.Dump();
|
||||||
|
printf("\ninvalid value %Ld in tree: ",value);
|
||||||
|
bailOutWithKey(key,length);
|
||||||
|
}
|
||||||
|
if (gKeys[value].value != value) {
|
||||||
|
iterator.Dump();
|
||||||
|
printf("\nkey pointing to the wrong value %Ld (should be %Ld)\n",value,gKeys[value].value);
|
||||||
|
bailOutWithKey(key,length);
|
||||||
|
}
|
||||||
|
if (length != gKeys[value].length
|
||||||
|
|| memcmp(key,gKeys[value].data,length)) {
|
||||||
|
iterator.Dump();
|
||||||
|
printf("\nkeys don't match (key index = %Ld, %ld times in tree, %ld. occassion):\n\tfound: ",value,gKeys[value].in,gKeys[value].count + 1);
|
||||||
|
dumpKey(key,length);
|
||||||
|
printf("\n\texpected: ");
|
||||||
|
dumpKey(gKeys[value].data,gKeys[value].length);
|
||||||
|
putchar('\n');
|
||||||
|
bailOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
gKeys[value].count++;
|
||||||
|
}
|
||||||
|
if (status != B_ENTRY_NOT_FOUND) {
|
||||||
|
printf("TreeIterator::GetNext() returned: %s\n",strerror(status));
|
||||||
|
iterator.Dump();
|
||||||
|
bailOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
if (gKeys[i].in != gKeys[i].count) {
|
||||||
|
printf("Key ");
|
||||||
|
dumpKey(gKeys[i].data,gKeys[i].length);
|
||||||
|
printf(" found only %ld from %ld\n",gKeys[i].count,gKeys[i].in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
checkTreeIntegrity(BPlusTree *tree)
|
||||||
|
{
|
||||||
|
// simple test, just seeks down to every key - if it couldn't
|
||||||
|
// be found, something must be wrong
|
||||||
|
|
||||||
|
TreeIterator iterator(tree);
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
if (gKeys[i].in == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
status_t status = iterator.Find((uint8 *)gKeys[i].data,gKeys[i].length);
|
||||||
|
if (status != B_OK) {
|
||||||
|
printf("TreeIterator::Find() returned: %s\n",strerror(status));
|
||||||
|
bailOutWithKey(gKeys[i].data,gKeys[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
checkTree(BPlusTree *tree)
|
||||||
|
{
|
||||||
|
if (!gExcessive)
|
||||||
|
printf("* Check tree...\n");
|
||||||
|
|
||||||
|
checkTreeContents(tree);
|
||||||
|
checkTreeIntegrity(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
//
|
||||||
|
// The tree "torture" functions
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
addAllKeys(Transaction *transaction, BPlusTree *tree)
|
||||||
|
{
|
||||||
|
printf("*** Adding all keys to the tree...\n");
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
status_t status = tree->Insert(transaction,(uint8 *)gKeys[i].data,gKeys[i].length,gKeys[i].value);
|
||||||
|
if (status < B_OK) {
|
||||||
|
printf("BPlusTree::Insert() returned: %s\n",strerror(status));
|
||||||
|
printf("key: ");
|
||||||
|
dumpKey(gKeys[i].data,gKeys[i].length);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gKeys[i].in++;
|
||||||
|
gTreeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
removeAllKeys(Transaction *transaction, BPlusTree *tree)
|
||||||
|
{
|
||||||
|
printf("*** Removing all keys from the tree...\n");
|
||||||
|
for (int32 i = 0;i < gNum;i++) {
|
||||||
|
while (gKeys[i].in > 0) {
|
||||||
|
status_t status = tree->Remove(transaction, (uint8 *)gKeys[i].data,
|
||||||
|
gKeys[i].length, gKeys[i].value);
|
||||||
|
if (status < B_OK) {
|
||||||
|
printf("BPlusTree::Remove() returned: %s\n", strerror(status));
|
||||||
|
printf("key: ");
|
||||||
|
dumpKey(gKeys[i].data, gKeys[i].length);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gKeys[i].in--;
|
||||||
|
gTreeCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkTree(tree);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
duplicateTest(Transaction *transaction,BPlusTree *tree)
|
||||||
|
{
|
||||||
|
int32 index = int32(1.0 * gNum * rand() / RAND_MAX);
|
||||||
|
if (index == gNum)
|
||||||
|
index = gNum - 1;
|
||||||
|
|
||||||
|
printf("*** Duplicate test with key ");
|
||||||
|
dumpKey(gKeys[index].data,gKeys[index].length);
|
||||||
|
puts("...");
|
||||||
|
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
int32 insertTotal = 0;
|
||||||
|
for (int32 i = 0;i < 8;i++) {
|
||||||
|
int32 insertCount = int32(1000.0 * rand() / RAND_MAX);
|
||||||
|
if (gVerbose)
|
||||||
|
printf("* insert %ld to %ld old entries...\n",insertCount,insertTotal + gKeys[index].in);
|
||||||
|
|
||||||
|
for (int32 j = 0;j < insertCount;j++) {
|
||||||
|
status = tree->Insert(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,insertTotal);
|
||||||
|
if (status < B_OK) {
|
||||||
|
printf("BPlusTree::Insert() returned: %s\n",strerror(status));
|
||||||
|
bailOutWithKey(gKeys[index].data,gKeys[index].length);
|
||||||
|
}
|
||||||
|
insertTotal++;
|
||||||
|
gTreeCount++;
|
||||||
|
|
||||||
|
if (gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 count;
|
||||||
|
if (i < 7) {
|
||||||
|
count = int32(1000.0 * rand() / RAND_MAX);
|
||||||
|
if (count > insertTotal)
|
||||||
|
count = insertTotal;
|
||||||
|
} else
|
||||||
|
count = insertTotal;
|
||||||
|
|
||||||
|
if (gVerbose)
|
||||||
|
printf("* remove %ld from %ld entries...\n",count,insertTotal + gKeys[index].in);
|
||||||
|
|
||||||
|
for (int32 j = 0;j < count;j++) {
|
||||||
|
status_t status = tree->Remove(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,insertTotal - 1);
|
||||||
|
if (status < B_OK) {
|
||||||
|
printf("BPlusTree::Remove() returned: %s\n",strerror(status));
|
||||||
|
bailOutWithKey(gKeys[index].data,gKeys[index].length);
|
||||||
|
}
|
||||||
|
insertTotal--;
|
||||||
|
gTreeCount--;
|
||||||
|
|
||||||
|
if (gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
addRandomSet(Transaction *transaction,BPlusTree *tree,int32 num)
|
||||||
|
{
|
||||||
|
printf("*** Add random set to tree (%ld to %ld old entries)...\n",num,gTreeCount);
|
||||||
|
|
||||||
|
for (int32 i = 0;i < num;i++) {
|
||||||
|
int32 index = int32(1.0 * gNum * rand() / RAND_MAX);
|
||||||
|
if (index == gNum)
|
||||||
|
index = gNum - 1;
|
||||||
|
|
||||||
|
if (gVerbose)
|
||||||
|
printf("adding key %ld (%ld times in the tree)\n",index,gKeys[index].in);
|
||||||
|
|
||||||
|
status_t status = tree->Insert(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,gKeys[index].value);
|
||||||
|
if (status < B_OK) {
|
||||||
|
printf("BPlusTree::Insert() returned: %s\n",strerror(status));
|
||||||
|
bailOutWithKey(gKeys[index].data,gKeys[index].length);
|
||||||
|
}
|
||||||
|
gKeys[index].in++;
|
||||||
|
gTreeCount++;
|
||||||
|
|
||||||
|
if (gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
if (!gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
removeRandomSet(Transaction *transaction,BPlusTree *tree,int32 num)
|
||||||
|
{
|
||||||
|
printf("*** Remove random set from tree (%ld from %ld entries)...\n",num,gTreeCount);
|
||||||
|
|
||||||
|
int32 tries = 500;
|
||||||
|
|
||||||
|
for (int32 i = 0;i < num;i++) {
|
||||||
|
if (gTreeCount < 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int32 index = int32(1.0 * gNum * rand() / RAND_MAX);
|
||||||
|
if (index == gNum)
|
||||||
|
index = gNum - 1;
|
||||||
|
|
||||||
|
if (gKeys[index].in == 0) {
|
||||||
|
i--;
|
||||||
|
if (tries-- < 0)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gVerbose)
|
||||||
|
printf("removing key %ld (%ld times in the tree)\n",index,gKeys[index].in);
|
||||||
|
|
||||||
|
status_t status = tree->Remove(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,gKeys[index].value);
|
||||||
|
if (status < B_OK) {
|
||||||
|
printf("BPlusTree::Remove() returned: %s\n",strerror(status));
|
||||||
|
bailOutWithKey(gKeys[index].data,gKeys[index].length);
|
||||||
|
}
|
||||||
|
gKeys[index].in--;
|
||||||
|
gTreeCount--;
|
||||||
|
|
||||||
|
if (gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
if (!gExcessive)
|
||||||
|
checkTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(char *program)
|
||||||
|
{
|
||||||
|
if (strrchr(program,'/'))
|
||||||
|
program = strrchr(program,'/') + 1;
|
||||||
|
fprintf(stderr,"usage: %s [-veh] [-t type] [-n keys] [-i iterations] [-h times] [-r seed]\n"
|
||||||
|
"BFS B+Tree torture test\n"
|
||||||
|
"\t-t\ttype is one of string, int32, uint32, int64, uint64, float,\n"
|
||||||
|
"\t\tor double; defaults to string.\n"
|
||||||
|
"\t-n\tkeys is the number of keys to be used,\n"
|
||||||
|
"\t\tminimum is 1, defaults to %ld.\n"
|
||||||
|
"\t-i\titerations is the number of the test cycles, defaults to %ld.\n"
|
||||||
|
"\t-r\tthe seed for the random function, defaults to %ld.\n"
|
||||||
|
"\t-h\tremoves the keys and start over again for x times.\n"
|
||||||
|
"\t-e\texcessive validity tests: tree contents will be tested after every operation\n"
|
||||||
|
"\t-v\tfor verbose output.\n",
|
||||||
|
program, DEFAULT_NUM_KEYS, DEFAULT_ITERATIONS, gSeed);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc,char **argv)
|
||||||
|
{
|
||||||
|
char *program = argv[0];
|
||||||
|
|
||||||
|
while (*++argv)
|
||||||
|
{
|
||||||
|
char *arg = *argv;
|
||||||
|
if (*arg == '-')
|
||||||
|
{
|
||||||
|
if (arg[1] == '-')
|
||||||
|
usage(program);
|
||||||
|
|
||||||
|
while (*++arg && isalpha(*arg))
|
||||||
|
{
|
||||||
|
switch (*arg)
|
||||||
|
{
|
||||||
|
case 'v':
|
||||||
|
gVerbose = true;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
gExcessive = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if (*++argv == NULL)
|
||||||
|
usage(program);
|
||||||
|
|
||||||
|
if (!strcmp(*argv,"string"))
|
||||||
|
gType = S_STR_INDEX;
|
||||||
|
else if (!strcmp(*argv,"int32")
|
||||||
|
|| !strcmp(*argv,"int"))
|
||||||
|
gType = S_INT_INDEX;
|
||||||
|
else if (!strcmp(*argv,"uint32")
|
||||||
|
|| !strcmp(*argv,"uint"))
|
||||||
|
gType = S_UINT_INDEX;
|
||||||
|
else if (!strcmp(*argv,"int64")
|
||||||
|
|| !strcmp(*argv,"llong"))
|
||||||
|
gType = S_LONG_LONG_INDEX;
|
||||||
|
else if (!strcmp(*argv,"uint64")
|
||||||
|
|| !strcmp(*argv,"ullong"))
|
||||||
|
gType = S_ULONG_LONG_INDEX;
|
||||||
|
else if (!strcmp(*argv,"float"))
|
||||||
|
gType = S_FLOAT_INDEX;
|
||||||
|
else if (!strcmp(*argv,"double"))
|
||||||
|
gType = S_DOUBLE_INDEX;
|
||||||
|
else
|
||||||
|
usage(program);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
if (*++argv == NULL || !isdigit(**argv))
|
||||||
|
usage(program);
|
||||||
|
|
||||||
|
gNum = atoi(*argv);
|
||||||
|
if (gNum < 1)
|
||||||
|
gNum = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
if (*++argv == NULL || !isdigit(**argv))
|
||||||
|
usage(program);
|
||||||
|
|
||||||
|
gHard = atoi(*argv);
|
||||||
|
if (gHard < 1)
|
||||||
|
gHard = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
if (*++argv == NULL || !isdigit(**argv))
|
||||||
|
usage(program);
|
||||||
|
|
||||||
|
gIterations = atoi(*argv);
|
||||||
|
if (gIterations < 1)
|
||||||
|
gIterations = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (*++argv == NULL || !isdigit(**argv))
|
||||||
|
usage(program);
|
||||||
|
|
||||||
|
gSeed = atoi(*argv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we do want to have reproducible random keys
|
||||||
|
if (gVerbose)
|
||||||
|
printf("Set seed to %ld\n",gSeed);
|
||||||
|
srand(gSeed);
|
||||||
|
|
||||||
|
Inode inode("tree.data",gType | S_ALLOW_DUPS);
|
||||||
|
gVolume = inode.GetVolume();
|
||||||
|
Transaction transaction(gVolume,0);
|
||||||
|
|
||||||
|
init_cache(gVolume->Device(),gVolume->BlockSize());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create the tree, the keys, and add all keys to the tree initially
|
||||||
|
//
|
||||||
|
|
||||||
|
BPlusTree tree(&transaction,&inode);
|
||||||
|
status_t status;
|
||||||
|
if ((status = tree.InitCheck()) < B_OK) {
|
||||||
|
fprintf(stderr,"creating tree failed: %s\n",strerror(status));
|
||||||
|
bailOut();
|
||||||
|
}
|
||||||
|
printf("*** Creating %ld keys...\n",gNum);
|
||||||
|
if ((status = createKeys()) < B_OK) {
|
||||||
|
fprintf(stderr,"creating keys failed: %s\n",strerror(status));
|
||||||
|
bailOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gVerbose)
|
||||||
|
dumpKeys();
|
||||||
|
|
||||||
|
for (int32 j = 0; j < gHard; j++ ) {
|
||||||
|
addAllKeys(&transaction, &tree);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Run the tests (they will exit the app, if an error occurs)
|
||||||
|
//
|
||||||
|
|
||||||
|
for (int32 i = 0;i < gIterations;i++) {
|
||||||
|
printf("---------- Test iteration %ld ---------------------------------\n",i+1);
|
||||||
|
|
||||||
|
addRandomSet(&transaction,&tree,int32(1.0 * gNum * rand() / RAND_MAX));
|
||||||
|
removeRandomSet(&transaction,&tree,int32(1.0 * gNum * rand() / RAND_MAX));
|
||||||
|
duplicateTest(&transaction,&tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAllKeys(&transaction, &tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
// of course, we would have to free all our memory in a real application here...
|
||||||
|
|
||||||
|
// write the cache back to the tree
|
||||||
|
shutdown_cache(gVolume->Device(),gVolume->BlockSize());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user