Reworked memory allocation and network protocol. This gargantuan commit also reduces the default size of C0, and removes quite a bit of redundant logic and error handling.
The tests now pass, except that check_merge never terminates (it takes too long) and check_mergelarge still is not passing. For better luck running this version of the code, turn off stasis' concurrent buffer manager. We're doing something bad that leads to deadlocks with the concurrent buffer manager. Another (the same?) bug less-frequently leads to page corruption with the old stasis buffer manager. git-svn-id: svn+ssh://svn.corp.yahoo.com/yahoo/yrl/labs/pnuts/code/logstore@556 8dad8b1f-cf64-0410-95b6-bcf113ffbcfe
This commit is contained in:
parent
3c297d1a66
commit
940a6da6fe
22 changed files with 549 additions and 915 deletions
56
datapage.cpp
56
datapage.cpp
|
@ -86,13 +86,13 @@ void DataPage<TUPLE>::initialize(int xid)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class TUPLE>
|
template <class TUPLE>
|
||||||
bool DataPage<TUPLE>::append(int xid, TUPLE const & dat)
|
bool DataPage<TUPLE>::append(int xid, TUPLE const * dat)
|
||||||
{
|
{
|
||||||
assert(byte_offset >= HEADER_SIZE);
|
assert(byte_offset >= HEADER_SIZE);
|
||||||
assert(fix_pcount >= 1);
|
assert(fix_pcount >= 1);
|
||||||
|
|
||||||
//check if there is enough space (for the data length + data)
|
//check if there is enough space (for the data length + data)
|
||||||
int32_t blen = dat.byte_length() + sizeof(int32_t);
|
int32_t blen = dat->byte_length() + sizeof(int32_t);
|
||||||
if(PAGE_SIZE * fix_pcount - byte_offset < blen)
|
if(PAGE_SIZE * fix_pcount - byte_offset < blen)
|
||||||
{
|
{
|
||||||
//check if the record is too large
|
//check if the record is too large
|
||||||
|
@ -118,7 +118,7 @@ bool DataPage<TUPLE>::append(int xid, TUPLE const & dat)
|
||||||
byte_offset += sizeof(int32_t);
|
byte_offset += sizeof(int32_t);
|
||||||
|
|
||||||
//write the data
|
//write the data
|
||||||
byte * barr = dat.to_bytes();
|
byte * barr = dat->to_bytes();
|
||||||
if(!writebytes(xid, dsize, barr)) //if write fails, undo the previous write
|
if(!writebytes(xid, dsize, barr)) //if write fails, undo the previous write
|
||||||
{
|
{
|
||||||
byte_offset -= sizeof(int32_t);
|
byte_offset -= sizeof(int32_t);
|
||||||
|
@ -127,7 +127,8 @@ bool DataPage<TUPLE>::append(int xid, TUPLE const & dat)
|
||||||
if(PAGE_SIZE - (byte_offset % PAGE_SIZE) >= sizeof(int32_t))
|
if(PAGE_SIZE - (byte_offset % PAGE_SIZE) >= sizeof(int32_t))
|
||||||
{
|
{
|
||||||
dsize = 0;
|
dsize = 0;
|
||||||
writebytes(xid, sizeof(int32_t), (byte*)(&dsize));//this will succeed, since there is enough space on the page
|
int succ = writebytes(xid, sizeof(int32_t), (byte*)(&dsize));//this will succeed, since there is enough space on the page
|
||||||
|
assert(succ);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +139,9 @@ bool DataPage<TUPLE>::append(int xid, TUPLE const & dat)
|
||||||
if(PAGE_SIZE - (byte_offset % PAGE_SIZE) >= sizeof(int32_t))
|
if(PAGE_SIZE - (byte_offset % PAGE_SIZE) >= sizeof(int32_t))
|
||||||
{
|
{
|
||||||
dsize = 0;
|
dsize = 0;
|
||||||
writebytes(xid, sizeof(int32_t), (byte*)(&dsize));//this will succeed, since there is enough space on the page
|
int succ = writebytes(xid, sizeof(int32_t), (byte*)(&dsize));//this will succeed, since there is enough space on the page
|
||||||
|
assert(succ);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -205,12 +208,11 @@ bool DataPage<TUPLE>::recordRead(int xid, typename TUPLE::key_t key, size_t keyS
|
||||||
int match = -1;
|
int match = -1;
|
||||||
while((*buf=itr.getnext(xid)) != 0)
|
while((*buf=itr.getnext(xid)) != 0)
|
||||||
{
|
{
|
||||||
match = TUPLE::compare((*buf)->get_key(), key);
|
match = TUPLE::compare((*buf)->key(), key);
|
||||||
|
|
||||||
if(match<0) //keep searching
|
if(match<0) //keep searching
|
||||||
{
|
{
|
||||||
free((*buf)->keylen);
|
datatuple::freetuple(*buf);
|
||||||
free(*buf);
|
|
||||||
*buf=0;
|
*buf=0;
|
||||||
}
|
}
|
||||||
else if(match==0) //found
|
else if(match==0) //found
|
||||||
|
@ -219,8 +221,7 @@ bool DataPage<TUPLE>::recordRead(int xid, typename TUPLE::key_t key, size_t keyS
|
||||||
}
|
}
|
||||||
else // match > 0, then does not exist
|
else // match > 0, then does not exist
|
||||||
{
|
{
|
||||||
free((*buf)->keylen);
|
datatuple::freetuple(*buf);
|
||||||
free(*buf);
|
|
||||||
*buf = 0;
|
*buf = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -230,12 +231,9 @@ bool DataPage<TUPLE>::recordRead(int xid, typename TUPLE::key_t key, size_t keyS
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class TUPLE>
|
template <class TUPLE>
|
||||||
void DataPage<TUPLE>::readbytes(int xid, int32_t offset, int count, byte **data)
|
void DataPage<TUPLE>::readbytes(int xid, int32_t offset, int count, byte *data)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(*data==NULL)
|
|
||||||
*data = (byte*)malloc(count);
|
|
||||||
|
|
||||||
int32_t bytes_copied = 0;
|
int32_t bytes_copied = 0;
|
||||||
while(bytes_copied < count)
|
while(bytes_copied < count)
|
||||||
{
|
{
|
||||||
|
@ -251,7 +249,7 @@ void DataPage<TUPLE>::readbytes(int xid, int32_t offset, int count, byte **data)
|
||||||
int32_t copy_len = ( (PAGE_SIZE - page_offset < count - bytes_copied ) ? PAGE_SIZE - page_offset : count - bytes_copied);
|
int32_t copy_len = ( (PAGE_SIZE - page_offset < count - bytes_copied ) ? PAGE_SIZE - page_offset : count - bytes_copied);
|
||||||
|
|
||||||
byte * pb_ptr = stasis_page_byte_ptr_from_start(p, page_offset);
|
byte * pb_ptr = stasis_page_byte_ptr_from_start(p, page_offset);
|
||||||
memcpy((*data)+bytes_copied, pb_ptr, copy_len);
|
memcpy((data)+bytes_copied, pb_ptr, copy_len);
|
||||||
|
|
||||||
//release the page
|
//release the page
|
||||||
unlock(p->rwlatch);
|
unlock(p->rwlatch);
|
||||||
|
@ -425,10 +423,11 @@ TUPLE* DataPage<TUPLE>::RecordIterator::getnext(int xid)
|
||||||
readlock(p->rwlatch,0);
|
readlock(p->rwlatch,0);
|
||||||
|
|
||||||
int32_t *dsize_ptr;
|
int32_t *dsize_ptr;
|
||||||
|
int32_t scratch;
|
||||||
if(PAGE_SIZE - (offset % PAGE_SIZE) < sizeof(int32_t)) //int spread in two pages
|
if(PAGE_SIZE - (offset % PAGE_SIZE) < sizeof(int32_t)) //int spread in two pages
|
||||||
{
|
{
|
||||||
dsize_ptr = 0;
|
dsize_ptr = &scratch;
|
||||||
dp->readbytes(xid, offset, sizeof(int32_t), (byte**)(&dsize_ptr));
|
dp->readbytes(xid, offset, sizeof(int32_t), (byte*)dsize_ptr);
|
||||||
}
|
}
|
||||||
else //int in a single page
|
else //int in a single page
|
||||||
dsize_ptr = (int32_t*)stasis_page_byte_ptr_from_start(p, offset % PAGE_SIZE);
|
dsize_ptr = (int32_t*)stasis_page_byte_ptr_from_start(p, offset % PAGE_SIZE);
|
||||||
|
@ -442,10 +441,12 @@ TUPLE* DataPage<TUPLE>::RecordIterator::getnext(int xid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte* tb=0;
|
byte* tb = (byte*)malloc(*dsize_ptr);
|
||||||
dp->readbytes(xid, offset, *dsize_ptr, &tb);
|
dp->readbytes(xid, offset, *dsize_ptr, tb);
|
||||||
|
|
||||||
TUPLE *tup = TUPLE::from_bytes(tb);
|
TUPLE *tup = TUPLE::from_bytes(tb); // This version of from_bytes does not consume its argument.
|
||||||
|
|
||||||
|
free(tb);
|
||||||
|
|
||||||
offset += *dsize_ptr;
|
offset += *dsize_ptr;
|
||||||
|
|
||||||
|
@ -484,15 +485,18 @@ void DataPage<TUPLE>::RecordIterator::advance(int xid, int count)
|
||||||
readlock(p->rwlatch,0);
|
readlock(p->rwlatch,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pindex == dp->pcount - 1 && (PAGE_SIZE - (offset % PAGE_SIZE) < sizeof(int32_t)))
|
if(pindex == dp->pcount - 1 && (PAGE_SIZE - (offset % PAGE_SIZE) < sizeof(int32_t))) {
|
||||||
|
assert(!p); // XXX Otherwise, was leaking page. do we reach this branch in testing?
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
int32_t *dsize_ptr=0;
|
int32_t *dsize_ptr=0;
|
||||||
if(PAGE_SIZE - (offset % PAGE_SIZE) < sizeof(int32_t)) //int spread in two pages
|
int32_t scratch;
|
||||||
dp->readbytes(xid, offset, sizeof(int32_t), (byte**)(&dsize_ptr));
|
if(PAGE_SIZE - (offset % PAGE_SIZE) < sizeof(int32_t)) { //int spread in two pages
|
||||||
else //int in a single page
|
dsize_ptr = &scratch;
|
||||||
|
dp->readbytes(xid, offset, sizeof(int32_t), (byte*)dsize_ptr);
|
||||||
|
} else { //int in a single page
|
||||||
dsize_ptr = (int32_t*)stasis_page_byte_ptr_from_start(p, offset % PAGE_SIZE);
|
dsize_ptr = (int32_t*)stasis_page_byte_ptr_from_start(p, offset % PAGE_SIZE);
|
||||||
|
}
|
||||||
offset += sizeof(int32_t);
|
offset += sizeof(int32_t);
|
||||||
|
|
||||||
if(*dsize_ptr == 0) //no more keys
|
if(*dsize_ptr == 0) //no more keys
|
||||||
|
|
|
@ -59,7 +59,7 @@ public:
|
||||||
|
|
||||||
~DataPage();
|
~DataPage();
|
||||||
|
|
||||||
bool append(int xid, TUPLE const & dat);
|
bool append(int xid, TUPLE const * dat);
|
||||||
bool recordRead(int xid, typename TUPLE::key_t key, size_t keySize, TUPLE ** buf);
|
bool recordRead(int xid, typename TUPLE::key_t key, size_t keySize, TUPLE ** buf);
|
||||||
|
|
||||||
inline uint16_t recordCount(int xid);
|
inline uint16_t recordCount(int xid);
|
||||||
|
@ -89,10 +89,10 @@ private:
|
||||||
void incrementPageCount(int xid, pageid_t pid, int add=1);
|
void incrementPageCount(int xid, pageid_t pid, int add=1);
|
||||||
|
|
||||||
bool writebytes(int xid, int count, byte *data);
|
bool writebytes(int xid, int count, byte *data);
|
||||||
inline void readbytes(int xid, int32_t offset, int count, byte **data=0);
|
inline void readbytes(int xid, int32_t offset, int count, byte *data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int pcount;
|
int32_t pcount;
|
||||||
pageid_t *pidarr;
|
pageid_t *pidarr;
|
||||||
int32_t byte_offset;//points to the next free byte
|
int32_t byte_offset;//points to the next free byte
|
||||||
|
|
||||||
|
|
204
datatuple.h
204
datatuple.h
|
@ -1,56 +1,54 @@
|
||||||
#ifndef _DATATUPLE_H_
|
#ifndef _DATATUPLE_H_
|
||||||
#define _DATATUPLE_H_
|
#define _DATATUPLE_H_
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
//#define byte unsigned char
|
|
||||||
typedef unsigned char byte;
|
typedef unsigned char byte;
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <assert.h>
|
||||||
//#include <stdio.h>
|
|
||||||
//#include <stdlib.h>
|
|
||||||
//#include <errno.h>
|
|
||||||
|
|
||||||
typedef struct datatuple
|
typedef struct datatuple
|
||||||
{
|
{
|
||||||
typedef uchar* key_t;
|
public:
|
||||||
typedef uchar* data_t;
|
typedef uint32_t len_t ;
|
||||||
static const size_t isize = sizeof(uint32_t);
|
typedef unsigned char* key_t ;
|
||||||
uint32_t *keylen; //key length should be size of string + 1 for \n
|
typedef unsigned char* data_t ;
|
||||||
uint32_t *datalen;
|
private:
|
||||||
key_t key;
|
static const len_t DELETE = ((len_t)0) - 1;
|
||||||
data_t data;
|
len_t datalen_;
|
||||||
|
byte* key_;
|
||||||
|
byte* data_; // aliases key. data_ - 1 should be the \0 terminating key_.
|
||||||
|
|
||||||
|
datatuple* sanity_check() {
|
||||||
|
assert(keylen() < 3000);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline len_t keylen() const {
|
||||||
|
return data_ - key_;
|
||||||
|
}
|
||||||
|
inline len_t datalen() const {
|
||||||
|
return (datalen_ == DELETE) ? 0 : datalen_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns the length of the byte array representation
|
||||||
|
len_t byte_length() const {
|
||||||
|
return sizeof(len_t) + sizeof(len_t) + keylen() + datalen();
|
||||||
|
}
|
||||||
|
static len_t length_from_header(len_t keylen, len_t datalen) {
|
||||||
|
return keylen + ((datalen == DELETE) ? 0 : datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline key_t key() const {
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
inline data_t data() const {
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
//this is used by the stl set
|
//this is used by the stl set
|
||||||
bool operator() (const datatuple& lhs, const datatuple& rhs) const
|
bool operator() (const datatuple* lhs, const datatuple* rhs) const {
|
||||||
{
|
return compare(lhs->key(), rhs->key()) < 0; //strcmp((char*)lhs.key(),(char*)rhs.key()) < 0;
|
||||||
//std::basic_string<uchar> s1(lhs.key);
|
|
||||||
//std::basic_string<uchar> s2(rhs.key);
|
|
||||||
return strcmp((char*)lhs.key,(char*)rhs.key) < 0;
|
|
||||||
//return (*((int32_t*)lhs.key)) <= (*((int32_t*)rhs.key));
|
|
||||||
}
|
|
||||||
|
|
||||||
void clone(const datatuple& tuple) {
|
|
||||||
//create a copy
|
|
||||||
|
|
||||||
byte * arr = (byte*) malloc(tuple.byte_length());
|
|
||||||
|
|
||||||
keylen = (uint32_t*) arr;
|
|
||||||
*keylen = *tuple.keylen;
|
|
||||||
datalen = (uint32_t*) (arr+isize);
|
|
||||||
*datalen = *tuple.datalen;
|
|
||||||
key = (datatuple::key_t) (arr+isize+isize);
|
|
||||||
memcpy((byte*)key, (byte*)tuple.key, *keylen);
|
|
||||||
if(!tuple.isDelete())
|
|
||||||
{
|
|
||||||
data = (datatuple::data_t) (arr+isize+isize+ *keylen);
|
|
||||||
memcpy((byte*)data, (byte*)tuple.data, *datalen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
data = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,28 +56,21 @@ typedef struct datatuple
|
||||||
* 0 if k1 == k2
|
* 0 if k1 == k2
|
||||||
* 1 of k1 > k2
|
* 1 of k1 > k2
|
||||||
**/
|
**/
|
||||||
static int compare(const key_t k1,const key_t k2)
|
static int compare(const byte* k1,const byte* k2) {
|
||||||
{
|
// XXX string comparison is probably not the right approach.
|
||||||
//for char* ending with \0
|
//for char* ending with \0
|
||||||
return strcmp((char*)k1,(char*)k2);
|
return strcmp((char*)k1,(char*)k2);
|
||||||
|
|
||||||
//for int32_t
|
|
||||||
//printf("%d\t%d\n",(*((int32_t*)k1)) ,(*((int32_t*)k2)));
|
|
||||||
//return (*((int32_t*)k1)) <= (*((int32_t*)k2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDelete()
|
inline void setDelete() {
|
||||||
{
|
datalen_ = DELETE;
|
||||||
*datalen = UINT_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isDelete() const
|
inline bool isDelete() const {
|
||||||
{
|
return datalen_ == DELETE;
|
||||||
return *datalen == UINT_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string key_to_str(const byte* k)
|
static std::string key_to_str(const byte* k) {
|
||||||
{
|
|
||||||
//for strings
|
//for strings
|
||||||
return std::string((char*)k);
|
return std::string((char*)k);
|
||||||
//for int
|
//for int
|
||||||
|
@ -90,75 +81,64 @@ typedef struct datatuple
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//returns the length of the byte array representation
|
//copy the tuple. does a deep copy of the contents.
|
||||||
int32_t byte_length() const{
|
datatuple* create_copy() const {
|
||||||
static const size_t isize = sizeof(uint32_t);
|
return create(key(), keylen(), data(), datalen_)->sanity_check();
|
||||||
if(isDelete())
|
}
|
||||||
return isize + *keylen + isize;
|
|
||||||
else
|
|
||||||
return isize + *keylen + isize + (*datalen);
|
static datatuple* create(const void* key, len_t keylen) {
|
||||||
|
return create(key, keylen, 0, DELETE)->sanity_check();
|
||||||
|
}
|
||||||
|
static datatuple* create(const void* key, len_t keylen, const void* data, len_t datalen) {
|
||||||
|
datatuple *ret = (datatuple*)malloc(sizeof(datatuple));
|
||||||
|
ret->key_ = (byte*)malloc(length_from_header(keylen, datalen));
|
||||||
|
memcpy(ret->key_, key, keylen);
|
||||||
|
ret->data_ = ret->key_ + keylen; // need to set this even if delete, since it encodes the key length.
|
||||||
|
if(datalen != DELETE) {
|
||||||
|
memcpy(ret->data_, data, datalen);
|
||||||
|
}
|
||||||
|
ret->datalen_ = datalen;
|
||||||
|
return ret->sanity_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
//format: key length _ data length _ key _ data
|
//format: key length _ data length _ key _ data
|
||||||
byte * to_bytes() const {
|
byte * to_bytes() const {
|
||||||
static const size_t isize = sizeof(uint32_t);
|
byte *ret = (byte*)malloc(byte_length());
|
||||||
byte * ret;
|
((len_t*)ret)[0] = keylen();
|
||||||
if(!isDelete())
|
((len_t*)ret)[1] = datalen_;
|
||||||
ret = (byte*) malloc(isize + *keylen + isize + *datalen);
|
memcpy(((len_t*)ret)+2, key_, length_from_header(keylen(), datalen_));
|
||||||
else
|
|
||||||
ret = (byte*) malloc(isize + *keylen + isize);
|
|
||||||
|
|
||||||
memcpy(ret, (byte*)(keylen), isize);
|
|
||||||
memcpy(ret+isize, (byte*)(datalen), isize);
|
|
||||||
memcpy(ret+isize+isize, key, *keylen);
|
|
||||||
if(!isDelete())
|
|
||||||
memcpy(ret+isize+isize+*keylen, data, *datalen);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//does not copy the data again
|
const byte* get_bytes(len_t *keylen, len_t *datalen) const {
|
||||||
//just sets the pointers in the datatuple to
|
*keylen = this->keylen();
|
||||||
//right positions in the given arr
|
*datalen = datalen_;
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
|
||||||
static datatuple* from_bytes(const byte * arr)
|
//format of buf: key _ data. The caller needs to 'peel' off key length and data length for this call.
|
||||||
{
|
static datatuple* from_bytes(len_t keylen, len_t datalen, byte* buf) {
|
||||||
static const size_t isize = sizeof(uint32_t);
|
|
||||||
datatuple *dt = (datatuple*) malloc(sizeof(datatuple));
|
datatuple *dt = (datatuple*) malloc(sizeof(datatuple));
|
||||||
|
dt->datalen_ = datalen;
|
||||||
dt->keylen = (uint32_t*) arr;
|
dt->key_ = buf;
|
||||||
dt->datalen = (uint32_t*) (arr+isize);
|
dt->data_ = dt->key_ + keylen;
|
||||||
dt->key = (key_t) (arr+isize+isize);
|
return dt->sanity_check();
|
||||||
if(!dt->isDelete())
|
|
||||||
dt->data = (data_t) (arr+isize+isize+ *(dt->keylen));
|
|
||||||
else
|
|
||||||
dt->data = 0;
|
|
||||||
|
|
||||||
return dt;
|
|
||||||
}
|
}
|
||||||
/*
|
static datatuple* from_bytes(byte* buf) {
|
||||||
static datatuple form_tuple(const byte * arr)
|
datatuple *dt = (datatuple*) malloc(sizeof(datatuple));
|
||||||
{
|
len_t keylen = ((len_t*)buf)[0];
|
||||||
static const size_t isize = sizeof(uint32_t);
|
dt->datalen_ = ((len_t*)buf)[1];
|
||||||
datatuple dt;
|
len_t buflen = length_from_header(keylen, dt->datalen_);
|
||||||
|
dt->key_ = (byte*)malloc(buflen);
|
||||||
|
memcpy(dt->key_,((len_t*)buf)+2,buflen);
|
||||||
|
dt->data_ = dt->key_ + keylen;
|
||||||
|
|
||||||
dt.keylen = (uint32_t*) arr;
|
return dt->sanity_check();
|
||||||
dt.datalen = (uint32_t*) (arr+isize);
|
|
||||||
dt.key = (key_t) (arr+isize+isize);
|
|
||||||
if(!dt.isDelete())
|
|
||||||
dt.data = (data_t) (arr+isize+isize+ *(dt.keylen));
|
|
||||||
else
|
|
||||||
dt.data = 0;
|
|
||||||
|
|
||||||
return dt;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
byte * get_key() { return (byte*) key; }
|
static inline void freetuple(datatuple* dt) {
|
||||||
byte * get_data() { return (byte*) data; }
|
free(dt->key_);
|
||||||
|
|
||||||
//releases only the tuple
|
|
||||||
static void release(datatuple *dt)
|
|
||||||
{
|
|
||||||
free(dt);
|
free(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,8 @@ public:
|
||||||
if(done_) { return NULL; }
|
if(done_) { return NULL; }
|
||||||
if(first_) { first_ = 0;} else { it_++; }
|
if(first_) { first_ = 0;} else { it_++; }
|
||||||
if(it_==itend_) { done_= true; return NULL; }
|
if(it_==itend_) { done_= true; return NULL; }
|
||||||
TUPLE *t = new TUPLE();
|
|
||||||
t->clone(*it_);
|
return (*it_)->create_copy();
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
114
logserver.cpp
114
logserver.cpp
|
@ -45,6 +45,11 @@ void logserver::startserver(logtable *ltable)
|
||||||
worker_data->ready_queue = &ready_queue;
|
worker_data->ready_queue = &ready_queue;
|
||||||
worker_data->work_queue = &work_queue;
|
worker_data->work_queue = &work_queue;
|
||||||
|
|
||||||
|
#ifdef STATS_ENABLED
|
||||||
|
worker_data->num_reqs = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
worker_data->qlock = qlock;
|
worker_data->qlock = qlock;
|
||||||
|
|
||||||
worker_data->selcond = selcond;
|
worker_data->selcond = selcond;
|
||||||
|
@ -340,14 +345,14 @@ void *serverLoop(void *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
//start listening on the server socket
|
//start listening on the server socket
|
||||||
//second arg is the max number of coonections waiting in queue
|
//second arg is the max number of connections waiting in queue
|
||||||
if(listen(sockfd,SOMAXCONN)==-1)
|
if(listen(sockfd,SOMAXCONN)==-1)
|
||||||
{
|
{
|
||||||
printf("ERROR on listen.\n");
|
printf("ERROR on listen.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("LSM Server listenning...\n");
|
printf("LSM Server listening...\n");
|
||||||
|
|
||||||
*(sdata->server_socket) = sockfd;
|
*(sdata->server_socket) = sockfd;
|
||||||
int flag, result;
|
int flag, result;
|
||||||
|
@ -427,21 +432,22 @@ void * thread_work_fn( void * args)
|
||||||
}
|
}
|
||||||
|
|
||||||
//step 1: read the opcode
|
//step 1: read the opcode
|
||||||
uint8_t opcode;
|
network_op_t opcode = readopfromsocket(*(item->data->workitem), LOGSTORE_CLIENT_REQUEST);
|
||||||
ssize_t n = read(*(item->data->workitem), &opcode, sizeof(uint8_t));
|
if(opcode == LOGSTORE_CONN_CLOSED_ERROR) {
|
||||||
if(n == 0) {
|
|
||||||
opcode = OP_DONE;
|
opcode = OP_DONE;
|
||||||
n = sizeof(uint8_t);
|
|
||||||
printf("Obsolescent client closed connection uncleanly\n");
|
printf("Obsolescent client closed connection uncleanly\n");
|
||||||
}
|
}
|
||||||
assert( n == sizeof(uint8_t));
|
|
||||||
assert( opcode < OP_INVALID );
|
|
||||||
|
|
||||||
if( opcode == OP_DONE ) //close the conn on failure
|
if( opcode == OP_DONE || (opiserror(opcode))) //close the conn on failure
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(item->data->qlock);
|
pthread_mutex_lock(item->data->qlock);
|
||||||
printf("client done. conn closed. (%d, %d, %d, %d)\n",
|
if(opiserror(opcode)) {
|
||||||
n, errno, *(item->data->workitem), item->data->work_queue->size());
|
printf("network error. conn closed. (%d, %d, %d, %d)\n",
|
||||||
|
opcode, errno, *(item->data->workitem), item->data->work_queue->size());
|
||||||
|
} else {
|
||||||
|
printf("client done. conn closed. (%d, %d)\n",
|
||||||
|
*(item->data->workitem), item->data->work_queue->size());
|
||||||
|
}
|
||||||
close(*(item->data->workitem));
|
close(*(item->data->workitem));
|
||||||
|
|
||||||
if(item->data->work_queue->size() > 0)
|
if(item->data->work_queue->size() > 0)
|
||||||
|
@ -465,29 +471,7 @@ void * thread_work_fn( void * args)
|
||||||
|
|
||||||
|
|
||||||
//step 2: read the tuple from client
|
//step 2: read the tuple from client
|
||||||
datatuple tuple;
|
datatuple * tuple = readtuplefromsocket(*(item->data->workitem));
|
||||||
tuple.keylen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
tuple.datalen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
|
|
||||||
//read the key length
|
|
||||||
n = read(*(item->data->workitem), tuple.keylen, sizeof(uint32_t));
|
|
||||||
assert( n == sizeof(uint32_t));
|
|
||||||
//read the data length
|
|
||||||
n = read(*(item->data->workitem), tuple.datalen, sizeof(uint32_t));
|
|
||||||
assert( n == sizeof(uint32_t));
|
|
||||||
|
|
||||||
//read the key
|
|
||||||
tuple.key = (byte*) malloc(*tuple.keylen);
|
|
||||||
readfromsocket(*(item->data->workitem), (char*) tuple.key, *tuple.keylen);
|
|
||||||
//read the data
|
|
||||||
if(!tuple.isDelete() && opcode != OP_FIND)
|
|
||||||
{
|
|
||||||
tuple.data = (byte*) malloc(*tuple.datalen);
|
|
||||||
readfromsocket(*(item->data->workitem), (char*) tuple.data, *tuple.datalen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tuple.data = 0;
|
|
||||||
|
|
||||||
//step 3: process the tuple
|
//step 3: process the tuple
|
||||||
//pthread_mutex_lock(item->data->table_lock);
|
//pthread_mutex_lock(item->data->table_lock);
|
||||||
//readlock(item->data->table_lock,0);
|
//readlock(item->data->table_lock,0);
|
||||||
|
@ -500,65 +484,59 @@ void * thread_work_fn( void * args)
|
||||||
//pthread_mutex_unlock(item->data->table_lock);
|
//pthread_mutex_unlock(item->data->table_lock);
|
||||||
//unlock(item->data->table_lock);
|
//unlock(item->data->table_lock);
|
||||||
//step 4: send response
|
//step 4: send response
|
||||||
uint8_t rcode = OP_SUCCESS;
|
uint8_t rcode = LOGSTORE_RESPONSE_SUCCESS;
|
||||||
n = write(*(item->data->workitem), &rcode, sizeof(uint8_t));
|
int err = writeoptosocket(*(item->data->workitem), LOGSTORE_RESPONSE_SUCCESS);
|
||||||
assert(n == sizeof(uint8_t));
|
if(err) {
|
||||||
|
perror("could not respond to client");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(opcode == OP_FIND)
|
else if(opcode == OP_FIND)
|
||||||
{
|
{
|
||||||
//find the tuple
|
//find the tuple
|
||||||
datatuple *dt = item->data->ltable->findTuple(-1, tuple.key, *tuple.keylen);
|
datatuple *dt = item->data->ltable->findTuple(-1, tuple->key(), tuple->keylen());
|
||||||
//unlock the lsmlock
|
//unlock the lsmlock
|
||||||
//pthread_mutex_unlock(item->data->table_lock);
|
//pthread_mutex_unlock(item->data->table_lock);
|
||||||
//unlock(item->data->table_lock);
|
//unlock(item->data->table_lock);
|
||||||
|
|
||||||
#ifdef STATS_ENABLED
|
#ifdef STATS_ENABLED
|
||||||
|
|
||||||
if(dt == 0)
|
if(dt == 0) {
|
||||||
DEBUG("key not found:\t%s\n", datatuple::key_to_str(tuple.key).c_str());
|
DEBUG("key not found:\t%s\n", datatuple::key_to_str(tuple.key()).c_str());
|
||||||
else if( *dt->datalen != 1024)
|
} else if( dt->datalen() != 1024) {
|
||||||
DEBUG("data len for\t%s:\t%d\n", datatuple::key_to_str(tuple.key).c_str(),
|
DEBUG("data len for\t%s:\t%d\n", datatuple::key_to_str(tuple.key()).c_str(),
|
||||||
*dt->datalen);
|
dt->datalen);
|
||||||
|
if(datatuple::compare(tuple->key(), dt->key()) != 0) {
|
||||||
if(datatuple::compare(tuple.key, dt->key) != 0)
|
DEBUG("key not equal:\t%s\t%s\n", datatuple::key_to_str(tuple.key()).c_str(),
|
||||||
DEBUG("key not equal:\t%s\t%s\n", datatuple::key_to_str(tuple.key).c_str(),
|
|
||||||
datatuple::key_to_str(dt->key).c_str());
|
datatuple::key_to_str(dt->key).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(dt == 0) //tuple deleted
|
bool dt_needs_free;
|
||||||
|
if(dt == 0) //tuple does not exist.
|
||||||
{
|
{
|
||||||
dt = (datatuple*) malloc(sizeof(datatuple));
|
dt = tuple;
|
||||||
dt->keylen = (uint32_t*) malloc(2*sizeof(uint32_t) + *tuple.keylen);
|
|
||||||
*dt->keylen = *tuple.keylen;
|
|
||||||
dt->datalen = dt->keylen + 1;
|
|
||||||
dt->key = (datatuple::key_t) (dt->datalen+1);
|
|
||||||
memcpy((byte*) dt->key, (byte*) tuple.key, *tuple.keylen);
|
|
||||||
dt->setDelete();
|
dt->setDelete();
|
||||||
|
dt_needs_free = false;
|
||||||
|
} else {
|
||||||
|
dt_needs_free = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//send the reply code
|
//send the reply code
|
||||||
uint8_t rcode = OP_SENDING_TUPLE;
|
int err = writeoptosocket(*(item->data->workitem), LOGSTORE_RESPONSE_SENDING_TUPLES);
|
||||||
n = write(*(item->data->workitem), &rcode, sizeof(uint8_t));
|
|
||||||
assert(n == sizeof(uint8_t));
|
|
||||||
|
|
||||||
//send the tuple
|
//send the tuple
|
||||||
writetosocket(*(item->data->workitem), (char*) dt->keylen, dt->byte_length());
|
writetupletosocket(*(item->data->workitem), dt);
|
||||||
|
|
||||||
//free datatuple
|
//free datatuple
|
||||||
free(dt->keylen);
|
if(dt_needs_free) {
|
||||||
free(dt);
|
datatuple::freetuple(dt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//close the socket
|
|
||||||
//close(*(item->data->workitem));
|
|
||||||
|
|
||||||
//free the tuple
|
//free the tuple
|
||||||
free(tuple.keylen);
|
datatuple::freetuple(tuple);
|
||||||
free(tuple.datalen);
|
|
||||||
free(tuple.key);
|
|
||||||
free(tuple.data);
|
|
||||||
|
|
||||||
//printf("socket %d: work completed.", *(item->data->workitem));
|
//printf("socket %d: work completed.", *(item->data->workitem));
|
||||||
|
|
||||||
|
@ -619,5 +597,3 @@ void * thread_work_fn( void * args)
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
17
logserver.h
17
logserver.h
|
@ -83,29 +83,12 @@ struct serverth_data
|
||||||
pthread_cond_t *selcond;
|
pthread_cond_t *selcond;
|
||||||
|
|
||||||
pthread_mutex_t *qlock;
|
pthread_mutex_t *qlock;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void * thread_work_fn( void *);
|
void * thread_work_fn( void *);
|
||||||
|
|
||||||
class logserver
|
class logserver
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
//server codes
|
|
||||||
// static uint8_t OP_SUCCESS;
|
|
||||||
// static uint8_t OP_FAIL;
|
|
||||||
// static uint8_t OP_SENDING_TUPLE;
|
|
||||||
//
|
|
||||||
// //client codes
|
|
||||||
// static uint8_t OP_FIND;
|
|
||||||
// static uint8_t OP_INSERT;
|
|
||||||
//
|
|
||||||
// static uint8_t OP_DONE;
|
|
||||||
//
|
|
||||||
// static uint8_t OP_INVALID;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
logserver(int nthreads, int server_port){
|
logserver(int nthreads, int server_port){
|
||||||
this->nthreads = nthreads;
|
this->nthreads = nthreads;
|
||||||
|
|
137
logstore.cpp
137
logstore.cpp
|
@ -8,6 +8,7 @@
|
||||||
#include "logiterators.h"
|
#include "logiterators.h"
|
||||||
#include "datapage.cpp"
|
#include "datapage.cpp"
|
||||||
|
|
||||||
|
#include <stasis/page.h>
|
||||||
#include <stasis/page/slotted.h>
|
#include <stasis/page/slotted.h>
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
|
@ -367,8 +368,11 @@ recordid logtree::appendPage(int xid, recordid tree, pageid_t & rmLeafID,
|
||||||
// NOTE: stasis_record_free call goes to slottedFree in slotted.c
|
// NOTE: stasis_record_free call goes to slottedFree in slotted.c
|
||||||
// this function only reduces the numslots when you call it
|
// this function only reduces the numslots when you call it
|
||||||
// with the last slot. so thats why i go backwards here.
|
// with the last slot. so thats why i go backwards here.
|
||||||
|
printf("slots %d (%d) keysize=%lld\n", (int)*stasis_page_slotted_numslots_ptr(p), (int)FIRST_SLOT+1, (long long int)keySize);
|
||||||
|
assert(*stasis_page_slotted_numslots_ptr(p) >= FIRST_SLOT+1);
|
||||||
for(int i = *stasis_page_slotted_numslots_ptr(p)-1; i>FIRST_SLOT; i--)
|
for(int i = *stasis_page_slotted_numslots_ptr(p)-1; i>FIRST_SLOT; i--)
|
||||||
{
|
{
|
||||||
|
assert(*stasis_page_slotted_numslots_ptr(p) > FIRST_SLOT+1);
|
||||||
const indexnode_rec *nr = (const indexnode_rec*)readRecord(xid,p,i,0);
|
const indexnode_rec *nr = (const indexnode_rec*)readRecord(xid,p,i,0);
|
||||||
int reclen = readRecordLength(xid, p, i);
|
int reclen = readRecordLength(xid, p, i);
|
||||||
recordid tmp_rec= {p->id, i, reclen};
|
recordid tmp_rec= {p->id, i, reclen};
|
||||||
|
@ -376,11 +380,15 @@ recordid logtree::appendPage(int xid, recordid tree, pageid_t & rmLeafID,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: could change with stasis_slotted_page_initialize(...);
|
//TODO: could change with stasis_slotted_page_initialize(...);
|
||||||
|
// TODO: fsck?
|
||||||
|
// stasis_page_slotted_initialize_page(p);
|
||||||
|
|
||||||
// reinsert first.
|
// reinsert first.
|
||||||
|
|
||||||
recordid pFirstSlot = { p->id, FIRST_SLOT, readRecordLength(xid, p, FIRST_SLOT)};
|
recordid pFirstSlot = { p->id, FIRST_SLOT, readRecordLength(xid, p, FIRST_SLOT)};
|
||||||
|
if(*stasis_page_slotted_numslots_ptr(p) != FIRST_SLOT+1) {
|
||||||
|
printf("slots %d (%d)\n", *stasis_page_slotted_numslots_ptr(p), (int)FIRST_SLOT+1);
|
||||||
assert(*stasis_page_slotted_numslots_ptr(p) == FIRST_SLOT+1);
|
assert(*stasis_page_slotted_numslots_ptr(p) == FIRST_SLOT+1);
|
||||||
|
}
|
||||||
|
|
||||||
indexnode_rec *nr
|
indexnode_rec *nr
|
||||||
= (indexnode_rec*)stasis_record_write_begin(xid, p, pFirstSlot);
|
= (indexnode_rec*)stasis_record_write_begin(xid, p, pFirstSlot);
|
||||||
|
@ -833,6 +841,21 @@ logtable::logtable()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logtable::tearDownTree(rbtree_ptr_t tree) {
|
||||||
|
datatuple * t = 0;
|
||||||
|
for(rbtree_t::iterator delitr = tree->begin();
|
||||||
|
delitr != tree->end();
|
||||||
|
delitr++) {
|
||||||
|
if(t) {
|
||||||
|
datatuple::freetuple(t);
|
||||||
|
}
|
||||||
|
t = *delitr;
|
||||||
|
tree->erase(delitr);
|
||||||
|
}
|
||||||
|
if(t) { datatuple::freetuple(t); }
|
||||||
|
delete tree;
|
||||||
|
}
|
||||||
|
|
||||||
logtable::~logtable()
|
logtable::~logtable()
|
||||||
{
|
{
|
||||||
if(tree_c1 != NULL)
|
if(tree_c1 != NULL)
|
||||||
|
@ -842,23 +865,10 @@ logtable::~logtable()
|
||||||
|
|
||||||
if(tree_c0 != NULL)
|
if(tree_c0 != NULL)
|
||||||
{
|
{
|
||||||
for(rbtree_t::iterator delitr=tree_c0->begin();
|
tearDownTree(tree_c0);
|
||||||
delitr != tree_c0->end(); delitr++)
|
|
||||||
free((*delitr).keylen);
|
|
||||||
|
|
||||||
delete tree_c0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete tmerger;
|
delete tmerger;
|
||||||
|
|
||||||
/*
|
|
||||||
if(rbtree_mut)
|
|
||||||
delete rbtree_mut;
|
|
||||||
if(tree_c0)
|
|
||||||
delete tree_c0;
|
|
||||||
if(input_needed)
|
|
||||||
delete input_needed;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recordid logtable::allocTable(int xid)
|
recordid logtable::allocTable(int xid)
|
||||||
|
@ -917,7 +927,7 @@ void logtable::flushTable()
|
||||||
while(*mergedata->old_c0) {
|
while(*mergedata->old_c0) {
|
||||||
unlock(mergedata->header_lock);
|
unlock(mergedata->header_lock);
|
||||||
// pthread_mutex_lock(mergedata->rbtree_mut);
|
// pthread_mutex_lock(mergedata->rbtree_mut);
|
||||||
if(tree_bytes >= MAX_C0_SIZE)
|
if(tree_bytes >= max_c0_size)
|
||||||
pthread_cond_wait(mergedata->input_needed_cond, mergedata->rbtree_mut);
|
pthread_cond_wait(mergedata->input_needed_cond, mergedata->rbtree_mut);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -974,13 +984,10 @@ void logtable::flushTable()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
datatuple * logtable::findTuple(int xid, const datatuple::key_t key, size_t keySize)
|
||||||
{
|
{
|
||||||
//prepare a search tuple
|
//prepare a search tuple
|
||||||
datatuple search_tuple;
|
datatuple *search_tuple = datatuple::create(key, keySize);
|
||||||
search_tuple.keylen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
*(search_tuple.keylen) = keySize;
|
|
||||||
search_tuple.key = key;
|
|
||||||
|
|
||||||
readlock(mergedata->header_lock,0);
|
readlock(mergedata->header_lock,0);
|
||||||
pthread_mutex_lock(mergedata->rbtree_mut);
|
pthread_mutex_lock(mergedata->rbtree_mut);
|
||||||
|
@ -992,10 +999,7 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
if(rbitr != tree_c0->end())
|
if(rbitr != tree_c0->end())
|
||||||
{
|
{
|
||||||
DEBUG("tree_c0 size %d\n", tree_c0->size());
|
DEBUG("tree_c0 size %d\n", tree_c0->size());
|
||||||
datatuple tuple = *rbitr;
|
ret_tuple = (*rbitr)->create_copy();
|
||||||
byte *barr = (byte*)malloc(tuple.byte_length());
|
|
||||||
memcpy(barr, (byte*)tuple.keylen, tuple.byte_length());
|
|
||||||
ret_tuple = datatuple::from_bytes(barr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
@ -1006,22 +1010,19 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
rbitr = (*(mergedata->old_c0))->find(search_tuple);
|
rbitr = (*(mergedata->old_c0))->find(search_tuple);
|
||||||
if(rbitr != (*(mergedata->old_c0))->end())
|
if(rbitr != (*(mergedata->old_c0))->end())
|
||||||
{
|
{
|
||||||
datatuple tuple = *rbitr;
|
datatuple *tuple = *rbitr;
|
||||||
|
|
||||||
if(tuple.isDelete()) //tuple deleted
|
if(tuple->isDelete()) //tuple deleted
|
||||||
done = true; //return ret_tuple
|
done = true; //return ret_tuple
|
||||||
else if(ret_tuple != 0) //merge the two
|
else if(ret_tuple != 0) //merge the two
|
||||||
{
|
{
|
||||||
datatuple *mtuple = tmerger->merge(&tuple, ret_tuple); //merge the two
|
datatuple *mtuple = tmerger->merge(tuple, ret_tuple); //merge the two
|
||||||
free(ret_tuple->keylen); //free tuple from current tree
|
datatuple::freetuple(ret_tuple); //free tuple from current tree
|
||||||
free(ret_tuple);
|
|
||||||
ret_tuple = mtuple; //set return tuple to merge result
|
ret_tuple = mtuple; //set return tuple to merge result
|
||||||
}
|
}
|
||||||
else //key first found in old mem tree
|
else //key first found in old mem tree
|
||||||
{
|
{
|
||||||
byte *barr = (byte*)malloc(tuple.byte_length());
|
ret_tuple = tuple->create_copy();
|
||||||
memcpy(barr, (byte*)tuple.keylen, tuple.byte_length());
|
|
||||||
ret_tuple = datatuple::from_bytes(barr);
|
|
||||||
}
|
}
|
||||||
//we cannot free tuple from old-tree 'cos it is not a copy
|
//we cannot free tuple from old-tree 'cos it is not a copy
|
||||||
}
|
}
|
||||||
|
@ -1042,8 +1043,7 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
else if(ret_tuple != 0) //merge the two
|
else if(ret_tuple != 0) //merge the two
|
||||||
{
|
{
|
||||||
datatuple *mtuple = tmerger->merge(tuple_c1, ret_tuple); //merge the two
|
datatuple *mtuple = tmerger->merge(tuple_c1, ret_tuple); //merge the two
|
||||||
free(ret_tuple->keylen); //free tuple from before
|
datatuple::freetuple(ret_tuple); //free tuple from before
|
||||||
free(ret_tuple);
|
|
||||||
ret_tuple = mtuple; //set return tuple to merge result
|
ret_tuple = mtuple; //set return tuple to merge result
|
||||||
}
|
}
|
||||||
else //found for the first time
|
else //found for the first time
|
||||||
|
@ -1057,8 +1057,7 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
|
|
||||||
if(!use_copy)
|
if(!use_copy)
|
||||||
{
|
{
|
||||||
free(tuple_c1->keylen); //free tuple from tree c1
|
datatuple::freetuple(tuple_c1); //free tuple from tree c1
|
||||||
free(tuple_c1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1078,8 +1077,7 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
else if(ret_tuple != 0) //merge the two
|
else if(ret_tuple != 0) //merge the two
|
||||||
{
|
{
|
||||||
datatuple *mtuple = tmerger->merge(tuple_oc1, ret_tuple); //merge the two
|
datatuple *mtuple = tmerger->merge(tuple_oc1, ret_tuple); //merge the two
|
||||||
free(ret_tuple->keylen); //free tuple from before
|
datatuple::freetuple(ret_tuple); //free tuple from before
|
||||||
free(ret_tuple);
|
|
||||||
ret_tuple = mtuple; //set return tuple to merge result
|
ret_tuple = mtuple; //set return tuple to merge result
|
||||||
}
|
}
|
||||||
else //found for the first time
|
else //found for the first time
|
||||||
|
@ -1093,8 +1091,7 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
|
|
||||||
if(!use_copy)
|
if(!use_copy)
|
||||||
{
|
{
|
||||||
free(tuple_oc1->keylen); //free tuple from tree old c1
|
datatuple::freetuple(tuple_oc1); //free tuple from tree old c1
|
||||||
free(tuple_oc1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1113,31 +1110,25 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
else if(ret_tuple != 0)
|
else if(ret_tuple != 0)
|
||||||
{
|
{
|
||||||
datatuple *mtuple = tmerger->merge(tuple_c2, ret_tuple); //merge the two
|
datatuple *mtuple = tmerger->merge(tuple_c2, ret_tuple); //merge the two
|
||||||
free(ret_tuple->keylen); //free tuple from before
|
datatuple::freetuple(ret_tuple); //free tuple from before
|
||||||
free(ret_tuple);
|
|
||||||
ret_tuple = mtuple; //set return tuple to merge result
|
ret_tuple = mtuple; //set return tuple to merge result
|
||||||
}
|
}
|
||||||
else //found for the first time
|
else //found for the first time
|
||||||
{
|
{
|
||||||
use_copy = true;
|
use_copy = true;
|
||||||
ret_tuple = tuple_c2;
|
ret_tuple = tuple_c2;
|
||||||
//byte *barr = (byte*)malloc(tuple_c2->byte_length());
|
|
||||||
//memcpy(barr, (byte*)tuple_c2->keylen, tuple_c2->byte_length());
|
|
||||||
//ret_tuple = datatuple::from_bytes(barr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!use_copy)
|
if(!use_copy)
|
||||||
{
|
{
|
||||||
free(tuple_c2->keylen); //free tuple from tree c2
|
datatuple::freetuple(tuple_c2); //free tuple from tree c2
|
||||||
free(tuple_c2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//pthread_mutex_unlock(mergedata->rbtree_mut);
|
//pthread_mutex_unlock(mergedata->rbtree_mut);
|
||||||
unlock(mergedata->header_lock);
|
unlock(mergedata->header_lock);
|
||||||
free(search_tuple.keylen);
|
datatuple::freetuple(search_tuple);
|
||||||
|
|
||||||
return ret_tuple;
|
return ret_tuple;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1149,10 +1140,7 @@ datatuple * logtable::findTuple(int xid, datatuple::key_t key, size_t keySize)
|
||||||
datatuple * logtable::findTuple_first(int xid, datatuple::key_t key, size_t keySize)
|
datatuple * logtable::findTuple_first(int xid, datatuple::key_t key, size_t keySize)
|
||||||
{
|
{
|
||||||
//prepare a search tuple
|
//prepare a search tuple
|
||||||
datatuple search_tuple;
|
datatuple * search_tuple = datatuple::create(key, keySize);
|
||||||
search_tuple.keylen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
*(search_tuple.keylen) = keySize;
|
|
||||||
search_tuple.key = key;
|
|
||||||
|
|
||||||
pthread_mutex_lock(mergedata->rbtree_mut);
|
pthread_mutex_lock(mergedata->rbtree_mut);
|
||||||
|
|
||||||
|
@ -1163,10 +1151,7 @@ datatuple * logtable::findTuple_first(int xid, datatuple::key_t key, size_t keyS
|
||||||
if(rbitr != tree_c0->end())
|
if(rbitr != tree_c0->end())
|
||||||
{
|
{
|
||||||
DEBUG("tree_c0 size %d\n", tree_c0->size());
|
DEBUG("tree_c0 size %d\n", tree_c0->size());
|
||||||
datatuple tuple = *rbitr;
|
ret_tuple = (*rbitr)->create_copy();
|
||||||
byte *barr = (byte*)malloc(tuple.byte_length());
|
|
||||||
memcpy(barr, (byte*)tuple.keylen, tuple.byte_length());
|
|
||||||
ret_tuple = datatuple::from_bytes(barr);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1179,10 +1164,7 @@ datatuple * logtable::findTuple_first(int xid, datatuple::key_t key, size_t keyS
|
||||||
rbitr = (*(mergedata->old_c0))->find(search_tuple);
|
rbitr = (*(mergedata->old_c0))->find(search_tuple);
|
||||||
if(rbitr != (*(mergedata->old_c0))->end())
|
if(rbitr != (*(mergedata->old_c0))->end())
|
||||||
{
|
{
|
||||||
datatuple tuple = *rbitr;
|
ret_tuple = (*rbitr)->create_copy();
|
||||||
byte *barr = (byte*)malloc(tuple.byte_length());
|
|
||||||
memcpy(barr, (byte*)tuple.keylen, tuple.byte_length());
|
|
||||||
ret_tuple = datatuple::from_bytes(barr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,13 +1203,13 @@ datatuple * logtable::findTuple_first(int xid, datatuple::key_t key, size_t keyS
|
||||||
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mergedata->rbtree_mut);
|
pthread_mutex_unlock(mergedata->rbtree_mut);
|
||||||
free(search_tuple.keylen);
|
datatuple::freetuple(search_tuple);
|
||||||
|
|
||||||
return ret_tuple;
|
return ret_tuple;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void logtable::insertTuple(struct datatuple &tuple)
|
void logtable::insertTuple(datatuple *tuple)
|
||||||
{
|
{
|
||||||
//static int count = LATCH_INTERVAL;
|
//static int count = LATCH_INTERVAL;
|
||||||
//static int tsize = 0; //number of tuples
|
//static int tsize = 0; //number of tuples
|
||||||
|
@ -1240,29 +1222,27 @@ void logtable::insertTuple(struct datatuple &tuple)
|
||||||
rbtree_t::iterator rbitr = tree_c0->find(tuple);
|
rbtree_t::iterator rbitr = tree_c0->find(tuple);
|
||||||
if(rbitr != tree_c0->end())
|
if(rbitr != tree_c0->end())
|
||||||
{
|
{
|
||||||
datatuple pre_t = *rbitr;
|
datatuple *pre_t = *rbitr;
|
||||||
//do the merging
|
//do the merging
|
||||||
datatuple *new_t = tmerger->merge(&pre_t, &tuple);
|
datatuple *new_t = tmerger->merge(pre_t, tuple);
|
||||||
tree_c0->erase(pre_t); //remove the previous tuple
|
tree_c0->erase(pre_t); //remove the previous tuple
|
||||||
|
|
||||||
tree_c0->insert( *new_t); //insert the new tuple
|
tree_c0->insert(new_t); //insert the new tuple
|
||||||
|
|
||||||
//update the tree size (+ new_t size - pre_t size)
|
//update the tree size (+ new_t size - pre_t size)
|
||||||
tree_bytes += (new_t->byte_length() - pre_t.byte_length());
|
tree_bytes += (new_t->byte_length() - pre_t->byte_length());
|
||||||
|
|
||||||
free(pre_t.keylen); //free the previous tuple
|
datatuple::freetuple(pre_t); //free the previous tuple
|
||||||
free(new_t); // frees the malloc(sizeof(datatuple)) coming from merge
|
|
||||||
}
|
}
|
||||||
else //no tuple with same key exists in mem-tree
|
else //no tuple with same key exists in mem-tree
|
||||||
{
|
{
|
||||||
|
|
||||||
datatuple t;
|
datatuple *t = tuple->create_copy();
|
||||||
t.clone(tuple);
|
|
||||||
|
|
||||||
//insert tuple into the rbtree
|
//insert tuple into the rbtree
|
||||||
tree_c0->insert(t);
|
tree_c0->insert(t);
|
||||||
tsize++;
|
tsize++;
|
||||||
tree_bytes += t.byte_length() + RB_TREE_OVERHEAD;
|
tree_bytes += t->byte_length() + RB_TREE_OVERHEAD;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1276,7 +1256,7 @@ void logtable::insertTuple(struct datatuple &tuple)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(tree_bytes >= MAX_C0_SIZE )
|
if(tree_bytes >= max_c0_size )
|
||||||
{
|
{
|
||||||
DEBUG("tree size before merge %d tuples %lld bytes.\n", tsize, tree_bytes);
|
DEBUG("tree size before merge %d tuples %lld bytes.\n", tsize, tree_bytes);
|
||||||
pthread_mutex_unlock(mergedata->rbtree_mut);
|
pthread_mutex_unlock(mergedata->rbtree_mut);
|
||||||
|
@ -1300,7 +1280,7 @@ void logtable::insertTuple(struct datatuple &tuple)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DataPage<datatuple>* logtable::insertTuple(int xid, struct datatuple &tuple, recordid &dpstate, logtree *ltree)
|
DataPage<datatuple>* logtable::insertTuple(int xid, datatuple *tuple, recordid &dpstate, logtree *ltree)
|
||||||
{
|
{
|
||||||
|
|
||||||
//create a new data page
|
//create a new data page
|
||||||
|
@ -1326,8 +1306,8 @@ DataPage<datatuple>* logtable::insertTuple(int xid, struct datatuple &tuple, rec
|
||||||
//insert the record key and id of the first page of the datapage to the logtree
|
//insert the record key and id of the first page of the datapage to the logtree
|
||||||
Tread(xid,ltree->get_tree_state(), &alloc_conf);
|
Tread(xid,ltree->get_tree_state(), &alloc_conf);
|
||||||
logtree::appendPage(xid, ltree->get_root_rec(), ltree->lastLeaf,
|
logtree::appendPage(xid, ltree->get_root_rec(), ltree->lastLeaf,
|
||||||
tuple.get_key(),
|
tuple->key(),
|
||||||
*tuple.keylen,
|
tuple->keylen(),
|
||||||
ltree->alloc_region,
|
ltree->alloc_region,
|
||||||
&alloc_conf,
|
&alloc_conf,
|
||||||
dp->get_start_pid()
|
dp->get_start_pid()
|
||||||
|
@ -1507,6 +1487,7 @@ int logtreeIterator::next(int xid, lladdIterator_t *it)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
assert(!impl->p);
|
||||||
if(impl->t != NULL)
|
if(impl->t != NULL)
|
||||||
free(impl->t);
|
free(impl->t);
|
||||||
impl->t = 0;
|
impl->t = 0;
|
||||||
|
|
17
logstore.h
17
logstore.h
|
@ -41,7 +41,8 @@ double tv_to_double(struct timeval tv);
|
||||||
|
|
||||||
struct logtable_mergedata;
|
struct logtable_mergedata;
|
||||||
|
|
||||||
|
typedef std::set<datatuple*, datatuple> rbtree_t;
|
||||||
|
typedef rbtree_t* rbtree_ptr_t;
|
||||||
|
|
||||||
typedef struct RegionAllocConf_t
|
typedef struct RegionAllocConf_t
|
||||||
{
|
{
|
||||||
|
@ -174,11 +175,11 @@ public:
|
||||||
~logtable();
|
~logtable();
|
||||||
|
|
||||||
//user access functions
|
//user access functions
|
||||||
datatuple * findTuple(int xid, datatuple::key_t key, size_t keySize);
|
datatuple * findTuple(int xid, const datatuple::key_t key, size_t keySize);
|
||||||
|
|
||||||
datatuple * findTuple_first(int xid, datatuple::key_t key, size_t keySize);
|
datatuple * findTuple_first(int xid, datatuple::key_t key, size_t keySize);
|
||||||
|
|
||||||
void insertTuple(struct datatuple &tuple);
|
void insertTuple(struct datatuple *tuple);
|
||||||
|
|
||||||
|
|
||||||
//other class functions
|
//other class functions
|
||||||
|
@ -186,9 +187,11 @@ public:
|
||||||
|
|
||||||
void flushTable();
|
void flushTable();
|
||||||
|
|
||||||
DataPage<datatuple>* insertTuple(int xid, struct datatuple &tuple, recordid &dpstate,logtree *ltree);
|
static inline void tearDownTree(rbtree_ptr_t t);
|
||||||
|
|
||||||
datatuple * findTuple(int xid, datatuple::key_t key, size_t keySize, logtree *ltree);
|
DataPage<datatuple>* insertTuple(int xid, datatuple *tuple, recordid &dpstate,logtree *ltree);
|
||||||
|
|
||||||
|
datatuple * findTuple(int xid, const datatuple::key_t key, size_t keySize, logtree *ltree);
|
||||||
|
|
||||||
inline recordid & get_table_rec(){return table_rec;}
|
inline recordid & get_table_rec(){return table_rec;}
|
||||||
|
|
||||||
|
@ -198,8 +201,6 @@ public:
|
||||||
inline void set_tree_c1(logtree *t){tree_c1=t;}
|
inline void set_tree_c1(logtree *t){tree_c1=t;}
|
||||||
inline void set_tree_c2(logtree *t){tree_c2=t;}
|
inline void set_tree_c2(logtree *t){tree_c2=t;}
|
||||||
|
|
||||||
typedef std::set<datatuple, datatuple> rbtree_t;
|
|
||||||
typedef rbtree_t* rbtree_ptr_t;
|
|
||||||
inline rbtree_ptr_t get_tree_c0(){return tree_c0;}
|
inline rbtree_ptr_t get_tree_c0(){return tree_c0;}
|
||||||
|
|
||||||
void set_tree_c0(rbtree_ptr_t newtree){tree_c0 = newtree;}
|
void set_tree_c0(rbtree_ptr_t newtree){tree_c0 = newtree;}
|
||||||
|
@ -233,6 +234,8 @@ public:
|
||||||
|
|
||||||
logtable_mergedata * mergedata;
|
logtable_mergedata * mergedata;
|
||||||
|
|
||||||
|
int64_t max_c0_size;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
58
merger.cpp
58
merger.cpp
|
@ -3,12 +3,13 @@
|
||||||
#include "merger.h"
|
#include "merger.h"
|
||||||
#include "logiterators.cpp"
|
#include "logiterators.cpp"
|
||||||
#include "datapage.h"
|
#include "datapage.h"
|
||||||
|
|
||||||
//pageid_t merge_scheduler::C0_MEM_SIZE = 1000 * 1000 * 1000;
|
//pageid_t merge_scheduler::C0_MEM_SIZE = 1000 * 1000 * 1000;
|
||||||
|
|
||||||
//template <> struct merger_args<rbtree_t>;
|
//template <> struct merger_args<rbtree_t>;
|
||||||
//template <> struct merger_args<logtree>;
|
//template <> struct merger_args<logtree>;
|
||||||
inline DataPage<datatuple>*
|
inline DataPage<datatuple>*
|
||||||
insertTuple(int xid, DataPage<datatuple> *dp, datatuple &t,
|
insertTuple(int xid, DataPage<datatuple> *dp, datatuple *t,
|
||||||
logtable *ltable,
|
logtable *ltable,
|
||||||
logtree * ltree,
|
logtree * ltree,
|
||||||
recordid & dpstate,
|
recordid & dpstate,
|
||||||
|
@ -124,8 +125,9 @@ void merge_scheduler::shutdown()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void merge_scheduler::startlogtable(int index)
|
void merge_scheduler::startlogtable(int index, int64_t MAX_C0_SIZE)
|
||||||
{
|
{
|
||||||
|
|
||||||
logtable * ltable = mergedata[index].first;
|
logtable * ltable = mergedata[index].first;
|
||||||
struct logtable_mergedata *mdata = mergedata[index].second;
|
struct logtable_mergedata *mdata = mergedata[index].second;
|
||||||
|
|
||||||
|
@ -158,6 +160,8 @@ void merge_scheduler::startlogtable(int index)
|
||||||
recordid * oldridp = new recordid;
|
recordid * oldridp = new recordid;
|
||||||
*oldridp = NULLRID;
|
*oldridp = NULLRID;
|
||||||
|
|
||||||
|
ltable->max_c0_size = MAX_C0_SIZE;
|
||||||
|
|
||||||
logtree ** block1_scratch = new logtree*;
|
logtree ** block1_scratch = new logtree*;
|
||||||
*block1_scratch=0;
|
*block1_scratch=0;
|
||||||
|
|
||||||
|
@ -391,12 +395,12 @@ void* memMergeThread(void*arg)
|
||||||
double target_R = *(a->r_i);
|
double target_R = *(a->r_i);
|
||||||
double new_c1_size = npages * PAGE_SIZE;
|
double new_c1_size = npages * PAGE_SIZE;
|
||||||
assert(target_R >= MIN_R);
|
assert(target_R >= MIN_R);
|
||||||
if( (new_c1_size / MAX_C0_SIZE > target_R) ||
|
if( (new_c1_size / ltable->max_c0_size > target_R) ||
|
||||||
(a->max_size && new_c1_size > a->max_size ) )
|
(a->max_size && new_c1_size > a->max_size ) )
|
||||||
{
|
{
|
||||||
printf("mmt:\tsignaling C2 for merge\n");
|
printf("mmt:\tsignaling C2 for merge\n");
|
||||||
printf("mmt:\tnew_c1_size %.2f\tMAX_C0_SIZE %lld\ta->max_size %lld\t targetr %.2f \n", new_c1_size,
|
printf("mmt:\tnew_c1_size %.2f\tMAX_C0_SIZE %lld\ta->max_size %lld\t targetr %.2f \n", new_c1_size,
|
||||||
MAX_C0_SIZE, a->max_size, target_R);
|
ltable->max_c0_size, a->max_size, target_R);
|
||||||
|
|
||||||
// XXX need to report backpressure here!
|
// XXX need to report backpressure here!
|
||||||
while(*a->out_tree) {
|
while(*a->out_tree) {
|
||||||
|
@ -454,22 +458,10 @@ void* memMergeThread(void*arg)
|
||||||
|
|
||||||
//TODO: get the freeing outside of the lock
|
//TODO: get the freeing outside of the lock
|
||||||
//// ----------- Free in_tree
|
//// ----------- Free in_tree
|
||||||
for(rbtree_t::iterator delitr=deltree->begin();
|
logtable::tearDownTree(deltree);
|
||||||
delitr != deltree->end(); delitr++)
|
|
||||||
free((*delitr).keylen);
|
|
||||||
|
|
||||||
delete deltree;
|
|
||||||
//deltree = 0;
|
//deltree = 0;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
for(rbtree_t::iterator delitr=(*a->in_tree)->begin();
|
|
||||||
delitr != (*a->in_tree)->end(); delitr++)
|
|
||||||
free((*delitr).keylen);
|
|
||||||
|
|
||||||
delete *a->in_tree;
|
|
||||||
*a->in_tree = 0;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//pthread_mutex_unlock(a->block_ready_mut);
|
//pthread_mutex_unlock(a->block_ready_mut);
|
||||||
|
@ -580,7 +572,7 @@ void *diskMergeThread(void*arg)
|
||||||
merge_count++;
|
merge_count++;
|
||||||
*a->my_tree_size = mergedPages;
|
*a->my_tree_size = mergedPages;
|
||||||
//update the current optimal R value
|
//update the current optimal R value
|
||||||
*(a->r_i) = std::max(MIN_R, sqrt( (npages * 1.0) / (MAX_C0_SIZE/PAGE_SIZE) ) );
|
*(a->r_i) = std::max(MIN_R, sqrt( (npages * 1.0) / (ltable->max_c0_size/PAGE_SIZE) ) );
|
||||||
|
|
||||||
printf("dmt:\tmerge_count %d\t#written pages: %lld\n optimal r %.2f", merge_count, npages, *(a->r_i));
|
printf("dmt:\tmerge_count %d\t#written pages: %lld\n optimal r %.2f", merge_count, npages, *(a->r_i));
|
||||||
|
|
||||||
|
@ -664,55 +656,50 @@ int64_t merge_iterators(int xid,
|
||||||
DEBUG("tuple\t%lld: keylen %d datalen %d\n",
|
DEBUG("tuple\t%lld: keylen %d datalen %d\n",
|
||||||
ntuples, *(t2->keylen),*(t2->datalen) );
|
ntuples, *(t2->keylen),*(t2->datalen) );
|
||||||
|
|
||||||
while(t1 != 0 && datatuple::compare(t1->key, t2->key) < 0) // t1 is less than t2
|
while(t1 != 0 && datatuple::compare(t1->key(), t2->key()) < 0) // t1 is less than t2
|
||||||
{
|
{
|
||||||
//insert t1
|
//insert t1
|
||||||
dp = insertTuple(xid, dp, *t1, ltable, scratch_tree,
|
dp = insertTuple(xid, dp, t1, ltable, scratch_tree,
|
||||||
ltable->get_dpstate2(),
|
ltable->get_dpstate2(),
|
||||||
dpages, npages);
|
dpages, npages);
|
||||||
|
|
||||||
free(t1->keylen);
|
datatuple::freetuple(t1);
|
||||||
free(t1);
|
|
||||||
ntuples++;
|
ntuples++;
|
||||||
//advance itrA
|
//advance itrA
|
||||||
t1 = itrA->getnext();
|
t1 = itrA->getnext();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t1 != 0 && datatuple::compare(t1->key, t2->key) == 0)
|
if(t1 != 0 && datatuple::compare(t1->key(), t2->key()) == 0)
|
||||||
{
|
{
|
||||||
datatuple *mtuple = ltable->gettuplemerger()->merge(t1,t2);
|
datatuple *mtuple = ltable->gettuplemerger()->merge(t1,t2);
|
||||||
|
|
||||||
//insert merged tuple, drop deletes
|
//insert merged tuple, drop deletes
|
||||||
if(dropDeletes && !mtuple->isDelete())
|
if(dropDeletes && !mtuple->isDelete())
|
||||||
dp = insertTuple(xid, dp, *mtuple, ltable, scratch_tree, ltable->get_dpstate2(),
|
dp = insertTuple(xid, dp, mtuple, ltable, scratch_tree, ltable->get_dpstate2(),
|
||||||
dpages, npages);
|
dpages, npages);
|
||||||
|
|
||||||
free(t1->keylen);
|
datatuple::freetuple(t1);
|
||||||
free(t1);
|
|
||||||
t1 = itrA->getnext(); //advance itrA
|
t1 = itrA->getnext(); //advance itrA
|
||||||
free(mtuple->keylen);
|
datatuple::freetuple(mtuple);
|
||||||
free(mtuple);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//insert t2
|
//insert t2
|
||||||
dp = insertTuple(xid, dp, *t2, ltable, scratch_tree, ltable->get_dpstate2(),
|
dp = insertTuple(xid, dp, t2, ltable, scratch_tree, ltable->get_dpstate2(),
|
||||||
dpages, npages);
|
dpages, npages);
|
||||||
// cannot free any tuples here; they may still be read through a lookup
|
// cannot free any tuples here; they may still be read through a lookup
|
||||||
}
|
}
|
||||||
|
|
||||||
free(t2->keylen);
|
datatuple::freetuple(t2);
|
||||||
free(t2);
|
|
||||||
ntuples++;
|
ntuples++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(t1 != 0) // t1 is less than t2
|
while(t1 != 0) // t1 is less than t2
|
||||||
{
|
{
|
||||||
dp = insertTuple(xid, dp, *t1, ltable, scratch_tree, ltable->get_dpstate2(),
|
dp = insertTuple(xid, dp, t1, ltable, scratch_tree, ltable->get_dpstate2(),
|
||||||
dpages, npages);
|
dpages, npages);
|
||||||
|
|
||||||
free(t1->keylen);
|
datatuple::freetuple(t1);
|
||||||
free(t1);
|
|
||||||
ntuples++;
|
ntuples++;
|
||||||
//advance itrA
|
//advance itrA
|
||||||
t1 = itrA->getnext();
|
t1 = itrA->getnext();
|
||||||
|
@ -727,9 +714,8 @@ int64_t merge_iterators(int xid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline DataPage<datatuple>*
|
inline DataPage<datatuple>*
|
||||||
insertTuple(int xid, DataPage<datatuple> *dp, datatuple &t,
|
insertTuple(int xid, DataPage<datatuple> *dp, datatuple *t,
|
||||||
logtable *ltable,
|
logtable *ltable,
|
||||||
logtree * ltree,
|
logtree * ltree,
|
||||||
recordid & dpstate,
|
recordid & dpstate,
|
||||||
|
|
6
merger.h
6
merger.h
|
@ -7,12 +7,8 @@
|
||||||
#include "logstore.h"
|
#include "logstore.h"
|
||||||
#include "logiterators.h"
|
#include "logiterators.h"
|
||||||
|
|
||||||
typedef std::set<datatuple, datatuple> rbtree_t;
|
|
||||||
typedef rbtree_t* rbtree_ptr_t;
|
|
||||||
|
|
||||||
//TODO: 400 bytes overhead per tuple, this is nuts, check if this is true...
|
//TODO: 400 bytes overhead per tuple, this is nuts, check if this is true...
|
||||||
static const int RB_TREE_OVERHEAD = 400;
|
static const int RB_TREE_OVERHEAD = 400;
|
||||||
static const int64_t MAX_C0_SIZE = 800 *1024*1024; //max size of c0
|
|
||||||
static const double MIN_R = 3.0;
|
static const double MIN_R = 3.0;
|
||||||
//T is either logtree or red-black tree
|
//T is either logtree or red-black tree
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -91,7 +87,7 @@ public:
|
||||||
~merge_scheduler();
|
~merge_scheduler();
|
||||||
|
|
||||||
int addlogtable(logtable * ltable);
|
int addlogtable(logtable * ltable);
|
||||||
void startlogtable(int index);
|
void startlogtable(int index, int64_t MAX_C0_SIZE = 100*1024*1024);
|
||||||
|
|
||||||
struct logtable_mergedata *getMergeData(int index){return mergedata[index].second;}
|
struct logtable_mergedata *getMergeData(int index){return mergedata[index].second;}
|
||||||
|
|
||||||
|
|
143
network.h
143
network.h
|
@ -9,39 +9,156 @@
|
||||||
#define NETWORK_H_
|
#define NETWORK_H_
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
typedef uint8_t network_op_t;
|
||||||
|
|
||||||
//server codes
|
//server codes
|
||||||
static const uint8_t OP_SUCCESS = 1;
|
static const network_op_t LOGSTORE_FIRST_RESPONSE_CODE = 1;
|
||||||
static const uint8_t OP_FAIL = 2;
|
static const network_op_t LOGSTORE_RESPONSE_SUCCESS = 1;
|
||||||
static const uint8_t OP_SENDING_TUPLE = 3;
|
static const network_op_t LOGSTORE_RESPONSE_FAIL = 2;
|
||||||
|
static const network_op_t LOGSTORE_RESPONSE_SENDING_TUPLES = 3;
|
||||||
|
static const network_op_t LOGSTORE_LAST_RESPONSE_CODE = 3;
|
||||||
|
|
||||||
//client codes
|
//client codes
|
||||||
static const uint8_t OP_FIND = 4;
|
static const network_op_t LOGSTORE_FIRST_REQUEST_CODE = 8;
|
||||||
static const uint8_t OP_INSERT = 5;
|
static const network_op_t OP_INSERT = 8; // Create, Update, Delete
|
||||||
|
static const network_op_t OP_FIND = 9; // Read
|
||||||
|
|
||||||
static const uint8_t OP_DONE = 6;
|
static const network_op_t OP_DONE = 10; // Please close the connection.
|
||||||
|
static const network_op_t LOGSTORE_LAST_REQUEST_CODE = 10;
|
||||||
|
|
||||||
static const uint8_t OP_INVALID = 32;
|
//error codes
|
||||||
|
static const network_op_t LOGSTORE_FIRST_ERROR = 28;
|
||||||
|
static const network_op_t LOGSTORE_CONN_CLOSED_ERROR = 28; // Unexpected EOF
|
||||||
|
static const network_op_t LOGSTORE_SOCKET_ERROR = 29; // The OS returned an error.
|
||||||
|
static const network_op_t LOGSTORE_REMOTE_ERROR = 30; // The other side didn't like our request
|
||||||
|
static const network_op_t LOGSTORE_PROTOCOL_ERROR = 31; // The other side responeded with gibberish.
|
||||||
|
static const network_op_t LOGSTORE_LAST_ERROR = 31;
|
||||||
|
static const network_op_t OP_INVALID = 32;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LOGSTORE_CLIENT_REQUEST,
|
||||||
|
LOGSTORE_SERVER_RESPONSE
|
||||||
|
} logstore_opcode_type;
|
||||||
|
|
||||||
static inline void readfromsocket(int sockd, char *buf, int count)
|
static inline int readfromsocket(int sockd, void *buf, ssize_t count)
|
||||||
{
|
{
|
||||||
|
|
||||||
int n = 0;
|
ssize_t n = 0;
|
||||||
|
|
||||||
while( n < count )
|
while( n < count )
|
||||||
{
|
{
|
||||||
n += read( sockd, buf + n, count - n);
|
ssize_t i = read( sockd, ((byte*)buf) + n, count - n);
|
||||||
|
if(i == -1) {
|
||||||
|
perror("readfromsocket failed");
|
||||||
|
return errno;
|
||||||
|
} else if(i == 0) {
|
||||||
|
errno = EOF;
|
||||||
|
return errno;
|
||||||
}
|
}
|
||||||
|
n += i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void writetosocket(int sockd, char *buf, int count)
|
static inline int writetosocket(int sockd, const void *buf, ssize_t count)
|
||||||
{
|
{
|
||||||
int n = 0;
|
ssize_t n = 0;
|
||||||
|
|
||||||
while( n < count )
|
while( n < count )
|
||||||
{
|
{
|
||||||
n += write( sockd, buf + n, count - n);
|
ssize_t i = write( sockd, ((byte*)buf) + n, count - n);
|
||||||
|
if(i == -1) {
|
||||||
|
perror("writetosocket failed");
|
||||||
|
return errno;
|
||||||
|
} else if(i == 0) {
|
||||||
|
errno = EOF;
|
||||||
|
return errno;
|
||||||
}
|
}
|
||||||
|
n += i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool opiserror(network_op_t op) {
|
||||||
|
return (LOGSTORE_FIRST_ERROR <= op && op <= LOGSTORE_LAST_ERROR);
|
||||||
|
}
|
||||||
|
static inline bool opisrequest(network_op_t op) {
|
||||||
|
return (LOGSTORE_FIRST_REQUEST_CODE <= op && op <= LOGSTORE_LAST_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
static inline bool opisresponse(network_op_t op) {
|
||||||
|
return (LOGSTORE_FIRST_RESPONSE_CODE <= op && op <= LOGSTORE_LAST_RESPONSE_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline network_op_t readopfromsocket(int sockd, logstore_opcode_type type) {
|
||||||
|
network_op_t ret;
|
||||||
|
ssize_t n = read(sockd, &ret, sizeof(network_op_t));
|
||||||
|
if(n == sizeof(network_op_t)) {
|
||||||
|
// done.
|
||||||
|
} else if(n == 0) { // EOF
|
||||||
|
perror("Socket closed mid request.");
|
||||||
|
return LOGSTORE_CONN_CLOSED_ERROR;
|
||||||
|
} else {
|
||||||
|
assert(n == -1); // sizeof(network_op_t) is 1, so short reads are impossible.
|
||||||
|
perror("Could not read opcode from socket");
|
||||||
|
return LOGSTORE_SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
// sanity checking
|
||||||
|
switch(type) {
|
||||||
|
case LOGSTORE_CLIENT_REQUEST: {
|
||||||
|
if(!(opisrequest(ret) || opiserror(ret))) {
|
||||||
|
fprintf(stderr, "Read invalid request code %d\n", (int)ret);
|
||||||
|
if(opisresponse(ret)) {
|
||||||
|
fprintf(stderr, "(also, the request code is a valid response code)\n");
|
||||||
|
}
|
||||||
|
ret = LOGSTORE_PROTOCOL_ERROR;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case LOGSTORE_SERVER_RESPONSE: {
|
||||||
|
if(!(opisresponse(ret) || opiserror(ret))) {
|
||||||
|
fprintf(stderr, "Read invalid response code %d\n", (int)ret);
|
||||||
|
if(opisrequest(ret)) {
|
||||||
|
fprintf(stderr, "(also, the response code is a valid request code)\n");
|
||||||
|
}
|
||||||
|
ret = LOGSTORE_PROTOCOL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static inline int writeoptosocket(int sockd, network_op_t op) {
|
||||||
|
assert(opiserror(op) || opisrequest(op) || opisresponse(op));
|
||||||
|
return writetosocket(sockd, &op, sizeof(network_op_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline datatuple* readtuplefromsocket(int sockd) {
|
||||||
|
|
||||||
|
datatuple::len_t keylen, datalen, buflen;
|
||||||
|
|
||||||
|
if( readfromsocket(sockd, &keylen, sizeof(keylen)) ) return NULL;
|
||||||
|
if( readfromsocket(sockd, &datalen, sizeof(datalen)) ) return NULL;
|
||||||
|
|
||||||
|
buflen = datatuple::length_from_header(keylen, datalen);
|
||||||
|
byte* bytes = (byte*) malloc(buflen);
|
||||||
|
|
||||||
|
if( readfromsocket(sockd, bytes, buflen) ) return NULL;
|
||||||
|
|
||||||
|
return datatuple::from_bytes(keylen, datalen, bytes); // from_bytes consumes the buffer.
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int writetupletosocket(int sockd, const datatuple* tup) {
|
||||||
|
datatuple::len_t keylen, datalen;
|
||||||
|
|
||||||
|
const byte* buf = tup->get_bytes(&keylen, &datalen);
|
||||||
|
int err;
|
||||||
|
if(( err = writetosocket(sockd, &keylen, sizeof(keylen)) )) return err;
|
||||||
|
if(( err = writetosocket(sockd, &datalen, sizeof(datalen)) )) return err;
|
||||||
|
if(( err = writetosocket(sockd, buf, datatuple::length_from_header(keylen, datalen)) )) return err;
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* NETWORK_H_ */
|
#endif /* NETWORK_H_ */
|
||||||
|
|
35
server.cpp
35
server.cpp
|
@ -38,19 +38,14 @@ void terminate (int param)
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertProbeIter(int NUM_ENTRIES)
|
void initialize_server()
|
||||||
{
|
{
|
||||||
//signal handling
|
//signal handling
|
||||||
void (*prev_fn)(int);
|
void (*prev_fn)(int);
|
||||||
|
|
||||||
prev_fn = signal (SIGINT,terminate);
|
prev_fn = signal (SIGINT,terminate);
|
||||||
//if (prev_fn==SIG_IGN)
|
|
||||||
//signal (SIGTERM,SIG_IGN);
|
|
||||||
|
|
||||||
|
bufferManagerFileHandleType = BUFFER_MANAGER_FILE_HANDLE_PFILE;
|
||||||
sync();
|
|
||||||
|
|
||||||
bufferManagerNonBlockingSlowHandleType = IO_HANDLE_PFILE;
|
|
||||||
|
|
||||||
Tinit();
|
Tinit();
|
||||||
|
|
||||||
|
@ -59,8 +54,6 @@ void insertProbeIter(int NUM_ENTRIES)
|
||||||
mscheduler = new merge_scheduler;
|
mscheduler = new merge_scheduler;
|
||||||
logtable ltable;
|
logtable ltable;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int pcount = 40;
|
int pcount = 40;
|
||||||
ltable.set_fixed_page_count(pcount);
|
ltable.set_fixed_page_count(pcount);
|
||||||
|
|
||||||
|
@ -71,17 +64,14 @@ void insertProbeIter(int NUM_ENTRIES)
|
||||||
int lindex = mscheduler->addlogtable(<able);
|
int lindex = mscheduler->addlogtable(<able);
|
||||||
ltable.setMergeData(mscheduler->getMergeData(lindex));
|
ltable.setMergeData(mscheduler->getMergeData(lindex));
|
||||||
|
|
||||||
mscheduler->startlogtable(lindex);
|
int64_t c0_size = 1024 * 1024 * 10;
|
||||||
|
printf("warning: running w/ tiny c0 for testing"); // XXX
|
||||||
|
mscheduler->startlogtable(lindex, c0_size);
|
||||||
|
|
||||||
lserver = new logserver(10, 32432);
|
lserver = new logserver(10, 32432);
|
||||||
|
|
||||||
lserver->startserver(<able);
|
lserver->startserver(<able);
|
||||||
|
|
||||||
|
|
||||||
// Tdeinit();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,18 +80,7 @@ void insertProbeIter(int NUM_ENTRIES)
|
||||||
*/
|
*/
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
//insertProbeIter(25000);
|
initialize_server();
|
||||||
insertProbeIter(10000);
|
abort(); // can't get here.
|
||||||
/*
|
|
||||||
insertProbeIter(5000);
|
|
||||||
insertProbeIter(2500);
|
|
||||||
insertProbeIter(1000);
|
|
||||||
insertProbeIter(500);
|
|
||||||
insertProbeIter(1000);
|
|
||||||
insertProbeIter(100);
|
|
||||||
insertProbeIter(10);
|
|
||||||
*/
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,12 +78,17 @@ logstore_handle_t * logstore_client_open(const char *host, int portnum, int time
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void close_conn(logstore_handle_t *l) {
|
||||||
|
printf("read/write err.. conn closed.\n");
|
||||||
|
close(l->server_socket); //close the connection
|
||||||
|
l->server_socket = -1;
|
||||||
|
}
|
||||||
datatuple *
|
datatuple *
|
||||||
logstore_client_op(logstore_handle_t *l,
|
logstore_client_op(logstore_handle_t *l,
|
||||||
// int *server_socket,
|
// int *server_socket,
|
||||||
// struct sockaddr_in serveraddr,
|
// struct sockaddr_in serveraddr,
|
||||||
// struct hostent *server,
|
// struct hostent *server,
|
||||||
uint8_t opcode, datatuple &tuple)
|
uint8_t opcode, datatuple * tuple)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(l->server_socket < 0)
|
if(l->server_socket < 0)
|
||||||
|
@ -122,60 +127,27 @@ logstore_client_op(logstore_handle_t *l,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//send the opcode
|
//send the opcode
|
||||||
int n = write(l->server_socket, (byte*) &opcode, sizeof(uint8_t));
|
if( writetosocket(l->server_socket, &opcode, sizeof(opcode)) ) { close_conn(l); return 0; }
|
||||||
assert(n == sizeof(uint8_t));
|
|
||||||
|
|
||||||
//send the tuple
|
//send the tuple
|
||||||
n = write(l->server_socket, (byte*) tuple.keylen, sizeof(uint32_t));
|
if( writetupletosocket(l->server_socket, tuple) ) { close_conn(l); return 0; }
|
||||||
assert( n == sizeof(uint32_t));
|
|
||||||
|
|
||||||
n = write(l->server_socket, (byte*) tuple.datalen, sizeof(uint32_t));
|
network_op_t rcode = readopfromsocket(l->server_socket,LOGSTORE_SERVER_RESPONSE);
|
||||||
assert( n == sizeof(uint32_t));
|
|
||||||
|
|
||||||
writetosocket(l->server_socket, (char*) tuple.key, *tuple.keylen);
|
if( opiserror(rcode) ) { close_conn(l); return 0; }
|
||||||
if(!tuple.isDelete() && *tuple.datalen != 0)
|
|
||||||
writetosocket(l->server_socket, (char*) tuple.data, *tuple.datalen);
|
|
||||||
|
|
||||||
//printf("\nssocket %d ", *server_socket);
|
|
||||||
//read the reply code
|
|
||||||
uint8_t rcode;
|
|
||||||
n = read(l->server_socket, (byte*) &rcode, sizeof(uint8_t));
|
|
||||||
if( n <= 0 )
|
|
||||||
{
|
|
||||||
printf("read err.. conn closed.\n");
|
|
||||||
close(l->server_socket); //close the connection
|
|
||||||
l->server_socket = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//printf("rdone\n");
|
|
||||||
datatuple * ret;
|
datatuple * ret;
|
||||||
if(rcode == OP_SENDING_TUPLE)
|
|
||||||
{
|
|
||||||
datatuple *rcvdtuple = (datatuple*)malloc(sizeof(datatuple));
|
|
||||||
//read the keylen
|
|
||||||
rcvdtuple->keylen = (uint32_t*) malloc(sizeof(uint32_t));
|
|
||||||
n = read(l->server_socket, (char*) rcvdtuple->keylen, sizeof(uint32_t));
|
|
||||||
assert(n == sizeof(uint32_t));
|
|
||||||
//read the datalen
|
|
||||||
rcvdtuple->datalen = (uint32_t*) malloc(sizeof(uint32_t));
|
|
||||||
n = read(l->server_socket, (byte*) rcvdtuple->datalen, sizeof(uint32_t));
|
|
||||||
assert(n == sizeof(uint32_t));
|
|
||||||
//read key
|
|
||||||
rcvdtuple->key = (byte*) malloc(*rcvdtuple->keylen);
|
|
||||||
readfromsocket(l->server_socket, (char*) rcvdtuple->key, *rcvdtuple->keylen);
|
|
||||||
if(!rcvdtuple->isDelete())
|
|
||||||
{
|
|
||||||
//read key
|
|
||||||
rcvdtuple->data = (byte*) malloc(*rcvdtuple->datalen);
|
|
||||||
readfromsocket(l->server_socket, (char*) rcvdtuple->data, *rcvdtuple->datalen);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rcvdtuple;
|
if(rcode == LOGSTORE_RESPONSE_SENDING_TUPLES)
|
||||||
} else if(rcode == OP_SUCCESS) {
|
{
|
||||||
ret = &tuple;
|
ret = readtuplefromsocket(l->server_socket);
|
||||||
|
|
||||||
|
} else if(rcode == LOGSTORE_RESPONSE_SUCCESS) {
|
||||||
|
ret = tuple;
|
||||||
} else {
|
} else {
|
||||||
|
assert(rcode == LOGSTORE_RESPONSE_FAIL); // if this is an invalid response, we should have noticed above
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ logstore_handle_t * logstore_client_open(const char *host, int portnum, int time
|
||||||
|
|
||||||
datatuple * logstore_client_op(logstore_handle_t* l,
|
datatuple * logstore_client_op(logstore_handle_t* l,
|
||||||
uint8_t opcode,
|
uint8_t opcode,
|
||||||
datatuple &tuple);
|
datatuple *tuple);
|
||||||
|
|
||||||
int logstore_client_close(logstore_handle_t* l);
|
int logstore_client_close(logstore_handle_t* l);
|
||||||
|
|
||||||
|
|
|
@ -78,23 +78,7 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
//prepare the key
|
||||||
datatuple newtuple;
|
datatuple *newtuple = datatuple::create(key_arr[i].c_str(), key_arr[i].length()+1, data_arr[i].c_str(), data_arr[i].length()+1);
|
||||||
uint32_t keylen = key_arr[i].length()+1;
|
|
||||||
newtuple.keylen = &keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
|
||||||
for(size_t j=0; j<keylen-1; j++)
|
|
||||||
newtuple.key[j] = key_arr[i][j];
|
|
||||||
newtuple.key[keylen-1]='\0';
|
|
||||||
|
|
||||||
//prepare the data
|
|
||||||
uint32_t datalen = data_arr[i].length()+1;
|
|
||||||
newtuple.datalen = &datalen;
|
|
||||||
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
for(size_t j=0; j<datalen-1; j++)
|
|
||||||
newtuple.data[j] = data_arr[i][j];
|
|
||||||
newtuple.data[datalen-1]='\0';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
||||||
|
@ -103,7 +87,7 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
//newtuple.data,
|
//newtuple.data,
|
||||||
*newtuple.datalen);
|
*newtuple.datalen);
|
||||||
*/
|
*/
|
||||||
datasize += newtuple.byte_length();
|
datasize += newtuple->byte_length();
|
||||||
if(dp==NULL || !dp->append(xid, newtuple))
|
if(dp==NULL || !dp->append(xid, newtuple))
|
||||||
{
|
{
|
||||||
dpages++;
|
dpages++;
|
||||||
|
@ -145,43 +129,16 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
datatuple *dt=0;
|
datatuple *dt=0;
|
||||||
while( (dt=itr.getnext(xid)) != NULL)
|
while( (dt=itr.getnext(xid)) != NULL)
|
||||||
{
|
{
|
||||||
assert(*(dt->keylen) == key_arr[tuplenum].length()+1);
|
assert(dt->keylen() == key_arr[tuplenum].length()+1);
|
||||||
assert(*(dt->datalen) == data_arr[tuplenum].length()+1);
|
assert(dt->datalen() == data_arr[tuplenum].length()+1);
|
||||||
tuplenum++;
|
tuplenum++;
|
||||||
free(dt->keylen);
|
datatuple::freetuple(dt);
|
||||||
free(dt);
|
|
||||||
dt = 0;
|
dt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Reads completed.\n");
|
printf("Reads completed.\n");
|
||||||
/*
|
|
||||||
|
|
||||||
int64_t count = 0;
|
|
||||||
lladdIterator_t * it = logtreeIterator::open(xid, tree);
|
|
||||||
|
|
||||||
while(logtreeIterator::next(xid, it)) {
|
|
||||||
byte * key;
|
|
||||||
byte **key_ptr = &key;
|
|
||||||
int keysize = logtreeIterator::key(xid, it, (byte**)key_ptr);
|
|
||||||
|
|
||||||
pageid_t *value;
|
|
||||||
pageid_t **value_ptr = &value;
|
|
||||||
int valsize = lsmTreeIterator_value(xid, it, (byte**)value_ptr);
|
|
||||||
//printf("keylen %d key %s\n", keysize, (char*)(key)) ;
|
|
||||||
assert(valsize == sizeof(pageid_t));
|
|
||||||
assert(!mycmp(std::string((char*)key), arr[count]) && !mycmp(arr[count],std::string((char*)key)));
|
|
||||||
assert(keysize == arr[count].length()+1);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
assert(count == NUM_ENTRIES);
|
|
||||||
|
|
||||||
logtreeIterator::close(xid, it);
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Tcommit(xid);
|
Tcommit(xid);
|
||||||
Tdeinit();
|
Tdeinit();
|
||||||
|
|
|
@ -77,32 +77,10 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
std::vector<pageid_t> dsp;
|
std::vector<pageid_t> dsp;
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
//prepare the tuple
|
||||||
datatuple newtuple;
|
datatuple* newtuple = datatuple::create(key_arr[i].c_str(), key_arr[i].length()+1, data_arr[i].c_str(), data_arr[i].length()+1);
|
||||||
uint32_t keylen = key_arr[i].length()+1;
|
|
||||||
newtuple.keylen = &keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
datasize += newtuple->byte_length();
|
||||||
for(size_t j=0; j<keylen-1; j++)
|
|
||||||
newtuple.key[j] = key_arr[i][j];
|
|
||||||
newtuple.key[keylen-1]='\0';
|
|
||||||
|
|
||||||
//prepare the data
|
|
||||||
uint32_t datalen = data_arr[i].length()+1;
|
|
||||||
newtuple.datalen = &datalen;
|
|
||||||
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
for(size_t j=0; j<datalen-1; j++)
|
|
||||||
newtuple.data[j] = data_arr[i][j];
|
|
||||||
newtuple.data[datalen-1]='\0';
|
|
||||||
|
|
||||||
// printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
|
||||||
//newtuple.key,
|
|
||||||
// *newtuple.keylen,
|
|
||||||
//newtuple.data,
|
|
||||||
// *newtuple.datalen);
|
|
||||||
|
|
||||||
datasize += newtuple.byte_length();
|
|
||||||
|
|
||||||
if(dp == NULL)
|
if(dp == NULL)
|
||||||
{
|
{
|
||||||
|
@ -122,10 +100,7 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(newtuple.key);
|
datatuple::freetuple(newtuple);
|
||||||
free(newtuple.data);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nTREE STRUCTURE\n");
|
printf("\nTREE STRUCTURE\n");
|
||||||
|
@ -139,13 +114,8 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
Tcommit(xid);
|
Tcommit(xid);
|
||||||
xid = Tbegin();
|
xid = Tbegin();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
printf("Stage 2: Sequentially reading %d tuples\n", NUM_ENTRIES);
|
printf("Stage 2: Sequentially reading %d tuples\n", NUM_ENTRIES);
|
||||||
|
|
||||||
|
|
||||||
size_t tuplenum = 0;
|
size_t tuplenum = 0;
|
||||||
treeIterator<datatuple> tree_itr(tree_root);
|
treeIterator<datatuple> tree_itr(tree_root);
|
||||||
|
|
||||||
|
@ -153,11 +123,10 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
datatuple *dt=0;
|
datatuple *dt=0;
|
||||||
while( (dt=tree_itr.getnext()) != NULL)
|
while( (dt=tree_itr.getnext()) != NULL)
|
||||||
{
|
{
|
||||||
assert(*(dt->keylen) == key_arr[tuplenum].length()+1);
|
assert(dt->keylen() == key_arr[tuplenum].length()+1);
|
||||||
assert(*(dt->datalen) == data_arr[tuplenum].length()+1);
|
assert(dt->datalen() == data_arr[tuplenum].length()+1);
|
||||||
tuplenum++;
|
tuplenum++;
|
||||||
free(dt->keylen);
|
datatuple::freetuple(dt);
|
||||||
free(dt);
|
|
||||||
dt = 0;
|
dt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,21 +142,12 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
//randomly pick a key
|
//randomly pick a key
|
||||||
int ri = rand()%key_arr.size();
|
int ri = rand()%key_arr.size();
|
||||||
|
|
||||||
//get the key
|
datatuple *dt = ltable.findTuple(xid, (const datatuple::key_t) key_arr[ri].c_str(), (size_t)key_arr[ri].length()+1, lt);
|
||||||
uint32_t keylen = key_arr[ri].length()+1;
|
|
||||||
datatuple::key_t rkey = (datatuple::key_t) malloc(keylen);
|
|
||||||
for(size_t j=0; j<keylen-1; j++)
|
|
||||||
rkey[j] = key_arr[ri][j];
|
|
||||||
rkey[keylen-1]='\0';
|
|
||||||
|
|
||||||
//find the key with the given tuple
|
|
||||||
datatuple *dt = ltable.findTuple(xid, rkey, keylen, lt);
|
|
||||||
|
|
||||||
assert(dt!=0);
|
assert(dt!=0);
|
||||||
assert(*(dt->keylen) == key_arr[ri].length()+1);
|
assert(dt->keylen() == key_arr[ri].length()+1);
|
||||||
assert(*(dt->datalen) == data_arr[ri].length()+1);
|
assert(dt->datalen() == data_arr[ri].length()+1);
|
||||||
free(dt->keylen);
|
datatuple::freetuple(dt);
|
||||||
free(dt);
|
|
||||||
dt = 0;
|
dt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,33 +72,13 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
|
|
||||||
struct timeval start_tv, stop_tv, ti_st, ti_end;
|
struct timeval start_tv, stop_tv, ti_st, ti_end;
|
||||||
double insert_time = 0;
|
double insert_time = 0;
|
||||||
int dpages = 0;
|
|
||||||
int npages = 0;
|
|
||||||
DataPage<datatuple> *dp=0;
|
|
||||||
int64_t datasize = 0;
|
int64_t datasize = 0;
|
||||||
std::vector<pageid_t> dsp;
|
std::vector<pageid_t> dsp;
|
||||||
gettimeofday(&start_tv,0);
|
gettimeofday(&start_tv,0);
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
//prepare the key
|
||||||
datatuple newtuple;
|
datatuple *newtuple = datatuple::create((*key_arr)[i].c_str(), (*key_arr)[i].length()+1,(*data_arr)[i].c_str(), (*data_arr)[i].length()+1);
|
||||||
uint32_t keylen = (*key_arr)[i].length()+1;
|
|
||||||
newtuple.keylen = &keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
|
||||||
memcpy((byte*)newtuple.key, (*key_arr)[i].c_str(), keylen);
|
|
||||||
//for(int j=0; j<keylen-1; j++)
|
|
||||||
// newtuple.key[j] = (*key_arr)[i][j];
|
|
||||||
//newtuple.key[keylen-1]='\0';
|
|
||||||
|
|
||||||
//prepare the data
|
|
||||||
uint32_t datalen = (*data_arr)[i].length()+1;
|
|
||||||
newtuple.datalen = &datalen;
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
memcpy((byte*)newtuple.data, (*data_arr)[i].c_str(), datalen);
|
|
||||||
// for(int j=0; j<datalen-1; j++)
|
|
||||||
// newtuple.data[j] = (*data_arr)[i][j];
|
|
||||||
// newtuple.data[datalen-1]='\0';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
||||||
|
@ -108,15 +88,14 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
*newtuple.datalen);
|
*newtuple.datalen);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
datasize += newtuple.byte_length();
|
datasize += newtuple->byte_length();
|
||||||
|
|
||||||
gettimeofday(&ti_st,0);
|
gettimeofday(&ti_st,0);
|
||||||
ltable.insertTuple(newtuple);
|
ltable.insertTuple(newtuple);
|
||||||
gettimeofday(&ti_end,0);
|
gettimeofday(&ti_end,0);
|
||||||
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
||||||
|
|
||||||
free(newtuple.key);
|
datatuple::freetuple(newtuple);
|
||||||
free(newtuple.data);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
gettimeofday(&stop_tv,0);
|
gettimeofday(&stop_tv,0);
|
||||||
|
@ -156,10 +135,9 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
//if(dt!=0)
|
//if(dt!=0)
|
||||||
{
|
{
|
||||||
found_tuples++;
|
found_tuples++;
|
||||||
assert(*(dt->keylen) == (*key_arr)[ri].length()+1);
|
assert(dt->keylen() == (*key_arr)[ri].length()+1);
|
||||||
assert(*(dt->datalen) == (*data_arr)[ri].length()+1);
|
assert(dt->datalen() == (*data_arr)[ri].length()+1);
|
||||||
free(dt->keylen);
|
datatuple::freetuple(dt);
|
||||||
free(dt);
|
|
||||||
}
|
}
|
||||||
dt = 0;
|
dt = 0;
|
||||||
free(rkey);
|
free(rkey);
|
||||||
|
|
|
@ -68,54 +68,26 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
|
|
||||||
struct timeval start_tv, stop_tv, ti_st, ti_end;
|
struct timeval start_tv, stop_tv, ti_st, ti_end;
|
||||||
double insert_time = 0;
|
double insert_time = 0;
|
||||||
int dpages = 0;
|
|
||||||
int npages = 0;
|
|
||||||
DataPage<datatuple> *dp=0;
|
|
||||||
int64_t datasize = 0;
|
int64_t datasize = 0;
|
||||||
std::vector<pageid_t> dsp;
|
std::vector<pageid_t> dsp;
|
||||||
gettimeofday(&start_tv,0);
|
gettimeofday(&start_tv,0);
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
|
||||||
datatuple newtuple;
|
|
||||||
uint32_t keylen = (*key_arr)[i].length()+1;
|
|
||||||
newtuple.keylen = &keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
|
||||||
memcpy((byte*)newtuple.key, (*key_arr)[i].c_str(), keylen);
|
|
||||||
//for(int j=0; j<keylen-1; j++)
|
|
||||||
// newtuple.key[j] = (*key_arr)[i][j];
|
|
||||||
//newtuple.key[keylen-1]='\0';
|
|
||||||
|
|
||||||
//prepare the data
|
//prepare the data
|
||||||
std::string ditem;
|
std::string ditem;
|
||||||
getnextdata(ditem, 10*8192);
|
getnextdata(ditem, 10*8192);
|
||||||
uint32_t datalen = ditem.length()+1;
|
|
||||||
newtuple.datalen = &datalen;
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
memcpy((byte*)newtuple.data, ditem.c_str(), datalen);
|
|
||||||
// for(int j=0; j<datalen-1; j++)
|
|
||||||
// newtuple.data[j] = (*data_arr)[i][j];
|
|
||||||
// newtuple.data[datalen-1]='\0';
|
|
||||||
|
|
||||||
/*
|
//prepare the tuple
|
||||||
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
datatuple *newtuple = datatuple::create((*key_arr)[i].c_str(), (*key_arr)[i].length()+1, ditem.c_str(), ditem.length()+1);
|
||||||
//newtuple.key,
|
|
||||||
*newtuple.keylen,
|
|
||||||
//newtuple.data,
|
|
||||||
*newtuple.datalen);
|
|
||||||
*/
|
|
||||||
|
|
||||||
datasize += newtuple.byte_length();
|
datasize += newtuple->byte_length();
|
||||||
|
|
||||||
gettimeofday(&ti_st,0);
|
gettimeofday(&ti_st,0);
|
||||||
ltable.insertTuple(newtuple);
|
ltable.insertTuple(newtuple);
|
||||||
gettimeofday(&ti_end,0);
|
gettimeofday(&ti_end,0);
|
||||||
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
||||||
|
|
||||||
free(newtuple.key);
|
datatuple::freetuple(newtuple);
|
||||||
free(newtuple.data);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
gettimeofday(&stop_tv,0);
|
gettimeofday(&stop_tv,0);
|
||||||
printf("insert time: %6.1f\n", insert_time);
|
printf("insert time: %6.1f\n", insert_time);
|
||||||
|
@ -124,52 +96,6 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
printf("\nTREE STRUCTURE\n");
|
printf("\nTREE STRUCTURE\n");
|
||||||
//ltable.get_tree_c1()->print_tree(xid);
|
//ltable.get_tree_c1()->print_tree(xid);
|
||||||
printf("datasize: %lld\n", datasize);
|
printf("datasize: %lld\n", datasize);
|
||||||
//sleep(20);
|
|
||||||
|
|
||||||
/*
|
|
||||||
//Tcommit(xid);
|
|
||||||
xid = Tbegin();
|
|
||||||
|
|
||||||
|
|
||||||
printf("Stage 2: Looking up %d keys:\n", NUM_ENTRIES);
|
|
||||||
|
|
||||||
int found_tuples=0;
|
|
||||||
for(int i=NUM_ENTRIES-1; i>=0; i--)
|
|
||||||
{
|
|
||||||
int ri = i;
|
|
||||||
//printf("key index%d\n", i);
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
//get the key
|
|
||||||
uint32_t keylen = (*key_arr)[ri].length()+1;
|
|
||||||
datatuple::key_t rkey = (datatuple::key_t) malloc(keylen);
|
|
||||||
memcpy((byte*)rkey, (*key_arr)[ri].c_str(), keylen);
|
|
||||||
//for(int j=0; j<keylen-1; j++)
|
|
||||||
//rkey[j] = (*key_arr)[ri][j];
|
|
||||||
//rkey[keylen-1]='\0';
|
|
||||||
|
|
||||||
//find the key with the given tuple
|
|
||||||
datatuple *dt = ltable.findTuple(xid, rkey, keylen);
|
|
||||||
|
|
||||||
assert(dt!=0);
|
|
||||||
//if(dt!=0)
|
|
||||||
{
|
|
||||||
found_tuples++;
|
|
||||||
assert(*(dt->keylen) == (*key_arr)[ri].length()+1);
|
|
||||||
//assert(*(dt->datalen) == (*data_arr)[ri].length()+1);
|
|
||||||
free(dt->keylen);
|
|
||||||
free(dt);
|
|
||||||
}
|
|
||||||
dt = 0;
|
|
||||||
free(rkey);
|
|
||||||
}
|
|
||||||
printf("found %d\n", found_tuples);
|
|
||||||
|
|
||||||
key_arr->clear();
|
|
||||||
//data_arr->clear();
|
|
||||||
delete key_arr;
|
|
||||||
//delete data_arr;
|
|
||||||
*/
|
|
||||||
|
|
||||||
mscheduler.shutdown();
|
mscheduler.shutdown();
|
||||||
printf("merge threads finished.\n");
|
printf("merge threads finished.\n");
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
void insertProbeIter(size_t NUM_ENTRIES)
|
void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
{
|
{
|
||||||
srand(1000);
|
srand(1000);
|
||||||
//unlink("storefile.txt");
|
unlink("storefile.txt");
|
||||||
//unlink("logfile.txt");
|
unlink("logfile.txt");
|
||||||
|
|
||||||
sync();
|
sync();
|
||||||
double delete_freq = .05;
|
double delete_freq = .05;
|
||||||
|
@ -91,11 +91,8 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
key_v_list->clear();
|
key_v_list->clear();
|
||||||
delete key_v_list;
|
delete key_v_list;
|
||||||
|
|
||||||
// preprandstr(NUM_ENTRIES, data_arr, 10*8192);
|
|
||||||
|
|
||||||
printf("key arr size: %d\n", key_arr->size());
|
printf("key arr size: %d\n", key_arr->size());
|
||||||
|
|
||||||
//removeduplicates(key_arr);
|
|
||||||
if(key_arr->size() > NUM_ENTRIES)
|
if(key_arr->size() > NUM_ENTRIES)
|
||||||
key_arr->erase(key_arr->begin()+NUM_ENTRIES, key_arr->end());
|
key_arr->erase(key_arr->begin()+NUM_ENTRIES, key_arr->end());
|
||||||
|
|
||||||
|
@ -138,45 +135,21 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
gettimeofday(&start_tv,0);
|
gettimeofday(&start_tv,0);
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
|
||||||
datatuple newtuple;
|
|
||||||
uint32_t keylen = (*key_arr)[i].length()+1;
|
|
||||||
newtuple.keylen = &keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
|
||||||
memcpy((byte*)newtuple.key, (*key_arr)[i].c_str(), keylen);
|
|
||||||
//for(int j=0; j<keylen-1; j++)
|
|
||||||
// newtuple.key[j] = (*key_arr)[i][j];
|
|
||||||
//newtuple.key[keylen-1]='\0';
|
|
||||||
|
|
||||||
//prepare the data
|
//prepare the data
|
||||||
std::string ditem;
|
std::string ditem;
|
||||||
getnextdata(ditem, 8192);
|
getnextdata(ditem, 8192);
|
||||||
uint32_t datalen = ditem.length()+1;
|
|
||||||
newtuple.datalen = &datalen;
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
memcpy((byte*)newtuple.data, ditem.c_str(), datalen);
|
|
||||||
// for(int j=0; j<datalen-1; j++)
|
|
||||||
// newtuple.data[j] = (*data_arr)[i][j];
|
|
||||||
// newtuple.data[datalen-1]='\0';
|
|
||||||
|
|
||||||
/*
|
//prepare the key
|
||||||
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
datatuple *newtuple = datatuple::create((*key_arr)[i].c_str(), (*key_arr)[i].length()+1, ditem.c_str(), ditem.length()+1);
|
||||||
//newtuple.key,
|
|
||||||
*newtuple.keylen,
|
|
||||||
//newtuple.data,
|
|
||||||
*newtuple.datalen);
|
|
||||||
*/
|
|
||||||
|
|
||||||
datasize += newtuple.byte_length();
|
datasize += newtuple->byte_length();
|
||||||
|
|
||||||
gettimeofday(&ti_st,0);
|
gettimeofday(&ti_st,0);
|
||||||
ltable.insertTuple(newtuple);
|
ltable.insertTuple(newtuple);
|
||||||
gettimeofday(&ti_end,0);
|
gettimeofday(&ti_end,0);
|
||||||
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
||||||
|
|
||||||
free(newtuple.key);
|
datatuple::freetuple(newtuple);
|
||||||
free(newtuple.data);
|
|
||||||
|
|
||||||
double rval = ((rand() % 100)+.0)/100;
|
double rval = ((rand() % 100)+.0)/100;
|
||||||
if( rval < delete_freq) //delete a key
|
if( rval < delete_freq) //delete a key
|
||||||
|
@ -185,22 +158,15 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
if(del_index >= 0 && std::find(del_list.begin(), del_list.end(), del_index) == del_list.end())
|
if(del_index >= 0 && std::find(del_list.begin(), del_list.end(), del_index) == del_list.end())
|
||||||
{
|
{
|
||||||
delcount++;
|
delcount++;
|
||||||
datatuple deltuple;
|
|
||||||
keylen = (*key_arr)[del_index].length()+1;
|
|
||||||
deltuple.keylen = &keylen;
|
|
||||||
|
|
||||||
deltuple.key = (datatuple::key_t) malloc(keylen);
|
datatuple *deltuple = datatuple::create((*key_arr)[del_index].c_str(), (*key_arr)[del_index].length()+1);
|
||||||
memcpy((byte*)deltuple.key, (*key_arr)[del_index].c_str(), keylen);
|
|
||||||
|
|
||||||
deltuple.datalen = &datalen;
|
|
||||||
deltuple.setDelete();
|
|
||||||
|
|
||||||
gettimeofday(&ti_st,0);
|
gettimeofday(&ti_st,0);
|
||||||
ltable.insertTuple(deltuple);
|
ltable.insertTuple(deltuple);
|
||||||
gettimeofday(&ti_end,0);
|
gettimeofday(&ti_end,0);
|
||||||
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
||||||
|
|
||||||
free(deltuple.key);
|
datatuple::freetuple(deltuple);
|
||||||
|
|
||||||
del_list.push_back(del_index);
|
del_list.push_back(del_index);
|
||||||
|
|
||||||
|
@ -211,28 +177,17 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
int up_index = i - (rand()%50); //update one of the last inserted 50 elements
|
int up_index = i - (rand()%50); //update one of the last inserted 50 elements
|
||||||
if(up_index >= 0 && std::find(del_list.begin(), del_list.end(), up_index) == del_list.end())
|
if(up_index >= 0 && std::find(del_list.begin(), del_list.end(), up_index) == del_list.end())
|
||||||
{//only update non-deleted elements
|
{//only update non-deleted elements
|
||||||
upcount++;
|
|
||||||
datatuple uptuple;
|
|
||||||
keylen = (*key_arr)[up_index].length()+1;
|
|
||||||
uptuple.keylen = &keylen;
|
|
||||||
|
|
||||||
uptuple.key = (datatuple::key_t) malloc(keylen);
|
|
||||||
memcpy((byte*)uptuple.key, (*key_arr)[up_index].c_str(), keylen);
|
|
||||||
|
|
||||||
getnextdata(ditem, 512);
|
getnextdata(ditem, 512);
|
||||||
datalen = ditem.length()+1;
|
|
||||||
uptuple.datalen = &datalen;
|
|
||||||
uptuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
memcpy((byte*)uptuple.data, ditem.c_str(), datalen);
|
|
||||||
|
|
||||||
|
upcount++;
|
||||||
|
datatuple *uptuple = datatuple::create((*key_arr)[up_index].c_str(), (*key_arr)[up_index].length()+1,
|
||||||
|
ditem.c_str(), ditem.length()+1);
|
||||||
gettimeofday(&ti_st,0);
|
gettimeofday(&ti_st,0);
|
||||||
ltable.insertTuple(uptuple);
|
ltable.insertTuple(uptuple);
|
||||||
gettimeofday(&ti_end,0);
|
gettimeofday(&ti_end,0);
|
||||||
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
||||||
|
|
||||||
free(uptuple.key);
|
datatuple::freetuple(uptuple);
|
||||||
free(uptuple.data);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -244,9 +199,7 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
printf("#deletions: %d\n#updates: %d\n", delcount, upcount);
|
printf("#deletions: %d\n#updates: %d\n", delcount, upcount);
|
||||||
|
|
||||||
printf("\nTREE STRUCTURE\n");
|
printf("\nTREE STRUCTURE\n");
|
||||||
//ltable.get_tree_c1()->print_tree(xid);
|
|
||||||
printf("datasize: %lld\n", datasize);
|
printf("datasize: %lld\n", datasize);
|
||||||
//sleep(20);
|
|
||||||
|
|
||||||
Tcommit(xid);
|
Tcommit(xid);
|
||||||
xid = Tbegin();
|
xid = Tbegin();
|
||||||
|
@ -259,16 +212,11 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
for(int i=NUM_ENTRIES-1; i>=0; i--)
|
for(int i=NUM_ENTRIES-1; i>=0; i--)
|
||||||
{
|
{
|
||||||
int ri = i;
|
int ri = i;
|
||||||
//printf("key index%d\n", i);
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
//get the key
|
//get the key
|
||||||
uint32_t keylen = (*key_arr)[ri].length()+1;
|
uint32_t keylen = (*key_arr)[ri].length()+1;
|
||||||
datatuple::key_t rkey = (datatuple::key_t) malloc(keylen);
|
datatuple::key_t rkey = (datatuple::key_t) malloc(keylen);
|
||||||
memcpy((byte*)rkey, (*key_arr)[ri].c_str(), keylen);
|
memcpy((byte*)rkey, (*key_arr)[ri].c_str(), keylen);
|
||||||
//for(int j=0; j<keylen-1; j++)
|
|
||||||
//rkey[j] = (*key_arr)[ri][j];
|
|
||||||
//rkey[keylen-1]='\0';
|
|
||||||
|
|
||||||
//find the key with the given tuple
|
//find the key with the given tuple
|
||||||
datatuple *dt = ltable.findTuple(xid, rkey, keylen);
|
datatuple *dt = ltable.findTuple(xid, rkey, keylen);
|
||||||
|
@ -278,19 +226,16 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
assert(dt!=0);
|
assert(dt!=0);
|
||||||
assert(!dt->isDelete());
|
assert(!dt->isDelete());
|
||||||
found_tuples++;
|
found_tuples++;
|
||||||
assert(*(dt->keylen) == (*key_arr)[ri].length()+1);
|
assert(dt->keylen() == (*key_arr)[ri].length()+1);
|
||||||
//assert(*(dt->datalen) == (*data_arr)[ri].length()+1);
|
datatuple::freetuple(dt);
|
||||||
free(dt->keylen);
|
|
||||||
free(dt);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(dt!=0)
|
if(dt!=0)
|
||||||
{
|
{
|
||||||
assert(*(dt->keylen) == (*key_arr)[ri].length()+1);
|
assert(dt->keylen() == (*key_arr)[ri].length()+1);
|
||||||
assert(dt->isDelete());
|
assert(dt->isDelete());
|
||||||
free(dt->keylen);
|
datatuple::freetuple(dt);
|
||||||
free(dt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dt = 0;
|
dt = 0;
|
||||||
|
@ -326,7 +271,7 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
*/
|
*/
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
//insertProbeIter(25000);
|
// insertProbeIter(25000);
|
||||||
insertProbeIter(400000);
|
insertProbeIter(400000);
|
||||||
/*
|
/*
|
||||||
insertProbeIter(5000);
|
insertProbeIter(5000);
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
|
|
||||||
void insertProbeIter(size_t NUM_ENTRIES)
|
void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
{
|
{
|
||||||
|
unlink("logfile.txt");
|
||||||
|
unlink("storefile.txt");
|
||||||
//data generation
|
//data generation
|
||||||
std::vector<std::string> data_arr;
|
std::vector<std::string> data_arr;
|
||||||
std::vector<std::string> key_arr;
|
std::vector<std::string> key_arr;
|
||||||
|
@ -38,45 +39,18 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
if(data_arr.size() > NUM_ENTRIES)
|
if(data_arr.size() > NUM_ENTRIES)
|
||||||
data_arr.erase(data_arr.begin()+NUM_ENTRIES, data_arr.end());
|
data_arr.erase(data_arr.begin()+NUM_ENTRIES, data_arr.end());
|
||||||
|
|
||||||
std::set<datatuple, datatuple> rbtree;
|
rbtree_t rbtree;
|
||||||
|
|
||||||
int64_t datasize = 0;
|
int64_t datasize = 0;
|
||||||
std::vector<pageid_t> dsp;
|
std::vector<pageid_t> dsp;
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
//prepare the key
|
||||||
datatuple newtuple;
|
datatuple *newtuple = datatuple::create(key_arr[i].c_str(), key_arr[i].length()+1,data_arr[i].c_str(), data_arr[i].length()+1);
|
||||||
uint32_t keylen = key_arr[i].length()+1;
|
|
||||||
newtuple.keylen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
*newtuple.keylen = keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
datasize += newtuple->byte_length();
|
||||||
for(size_t j=0; j<keylen-1; j++)
|
|
||||||
newtuple.key[j] = key_arr[i][j];
|
|
||||||
newtuple.key[keylen-1]='\0';
|
|
||||||
|
|
||||||
//prepare the data
|
|
||||||
uint32_t datalen = data_arr[i].length()+1;
|
|
||||||
newtuple.datalen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
*newtuple.datalen = datalen;
|
|
||||||
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
for(size_t j=0; j<datalen-1; j++)
|
|
||||||
newtuple.data[j] = data_arr[i][j];
|
|
||||||
newtuple.data[datalen-1]='\0';
|
|
||||||
|
|
||||||
/*
|
|
||||||
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
|
||||||
//newtuple.key,
|
|
||||||
*newtuple.keylen,
|
|
||||||
//newtuple.data,
|
|
||||||
*newtuple.datalen);
|
|
||||||
*/
|
|
||||||
|
|
||||||
datasize += newtuple.byte_length();
|
|
||||||
|
|
||||||
rbtree.insert(newtuple);
|
rbtree.insert(newtuple);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nTREE STRUCTURE\n");
|
printf("\nTREE STRUCTURE\n");
|
||||||
|
@ -88,47 +62,29 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
int found_tuples=0;
|
int found_tuples=0;
|
||||||
for(int i=NUM_ENTRIES-1; i>=0; i--)
|
for(int i=NUM_ENTRIES-1; i>=0; i--)
|
||||||
{
|
{
|
||||||
|
//find the key with the given tuple
|
||||||
int ri = i;
|
int ri = i;
|
||||||
|
|
||||||
//get the key
|
|
||||||
uint32_t keylen = key_arr[ri].length()+1;
|
|
||||||
datatuple::key_t rkey = (datatuple::key_t) malloc(keylen);
|
|
||||||
for(size_t j=0; j<keylen-1; j++)
|
|
||||||
rkey[j] = key_arr[ri][j];
|
|
||||||
rkey[keylen-1]='\0';
|
|
||||||
|
|
||||||
//find the key with the given tuple
|
|
||||||
|
|
||||||
//prepare a search tuple
|
//prepare a search tuple
|
||||||
datatuple search_tuple;
|
datatuple *search_tuple = datatuple::create(key_arr[ri].c_str(), key_arr[ri].length()+1);
|
||||||
search_tuple.keylen = (uint32_t*)malloc(sizeof(uint32_t));
|
|
||||||
*(search_tuple.keylen) = keylen;
|
|
||||||
search_tuple.key = rkey;
|
|
||||||
|
|
||||||
|
|
||||||
datatuple *ret_tuple=0;
|
|
||||||
//step 1: look in tree_c0
|
//step 1: look in tree_c0
|
||||||
|
|
||||||
rbtree_t::iterator rbitr = rbtree.find(search_tuple);
|
rbtree_t::iterator rbitr = rbtree.find(search_tuple);
|
||||||
if(rbitr != rbtree.end())
|
if(rbitr != rbtree.end())
|
||||||
{
|
{
|
||||||
datatuple tuple = *rbitr;
|
datatuple *tuple = *rbitr;
|
||||||
byte *barr = tuple.to_bytes();
|
|
||||||
ret_tuple = datatuple::from_bytes(barr);
|
|
||||||
|
|
||||||
found_tuples++;
|
found_tuples++;
|
||||||
assert(*(ret_tuple->keylen) == key_arr[ri].length()+1);
|
assert(tuple->keylen() == key_arr[ri].length()+1);
|
||||||
assert(*(ret_tuple->datalen) == data_arr[ri].length()+1);
|
assert(tuple->datalen() == data_arr[ri].length()+1);
|
||||||
free(barr);
|
|
||||||
free(ret_tuple);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Not in scratch_tree\n");
|
printf("Not in scratch_tree\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(search_tuple.keylen);
|
datatuple::freetuple(search_tuple);
|
||||||
free(rkey);
|
|
||||||
}
|
}
|
||||||
printf("found %d\n", found_tuples);
|
printf("found %d\n", found_tuples);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ static int svrport = 32432;
|
||||||
void insertProbeIter(size_t NUM_ENTRIES)
|
void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
{
|
{
|
||||||
srand(1000);
|
srand(1000);
|
||||||
// std::string servername = svrname; //"sherpa4";
|
|
||||||
// int serverport = svrport; //32432;
|
|
||||||
|
|
||||||
logstore_handle_t * l = logstore_client_open(svrname, svrport, 100);
|
logstore_handle_t * l = logstore_client_open(svrname, svrport, 100);
|
||||||
|
|
||||||
|
@ -97,12 +95,8 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
}
|
}
|
||||||
key_v_list->clear();
|
key_v_list->clear();
|
||||||
delete key_v_list;
|
delete key_v_list;
|
||||||
|
|
||||||
// preprandstr(NUM_ENTRIES, data_arr, 10*8192);
|
|
||||||
|
|
||||||
printf("key arr size: %d\n", key_arr->size());
|
printf("key arr size: %d\n", key_arr->size());
|
||||||
|
|
||||||
//removeduplicates(key_arr);
|
|
||||||
if(key_arr->size() > NUM_ENTRIES)
|
if(key_arr->size() > NUM_ENTRIES)
|
||||||
key_arr->erase(key_arr->begin()+NUM_ENTRIES, key_arr->end());
|
key_arr->erase(key_arr->begin()+NUM_ENTRIES, key_arr->end());
|
||||||
|
|
||||||
|
@ -122,35 +116,21 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
for(size_t i = 0; i < NUM_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
//prepare the key
|
//prepare the key
|
||||||
datatuple newtuple;
|
datatuple::len_t keylen = (*key_arr)[i].length()+1;
|
||||||
uint32_t keylen = (*key_arr)[i].length()+1;
|
|
||||||
newtuple.keylen = &keylen;
|
|
||||||
|
|
||||||
newtuple.key = (datatuple::key_t) malloc(keylen);
|
|
||||||
memcpy((byte*)newtuple.key, (*key_arr)[i].c_str(), keylen);
|
|
||||||
|
|
||||||
//prepare the data
|
//prepare the data
|
||||||
std::string ditem;
|
std::string ditem;
|
||||||
getnextdata(ditem, 8192);
|
getnextdata(ditem, 8192);
|
||||||
uint32_t datalen = ditem.length()+1;
|
datatuple::len_t datalen = ditem.length()+1;
|
||||||
newtuple.datalen = &datalen;
|
|
||||||
newtuple.data = (datatuple::data_t) malloc(datalen);
|
|
||||||
memcpy((byte*)newtuple.data, ditem.c_str(), datalen);
|
|
||||||
|
|
||||||
/*
|
datatuple* newtuple = datatuple::create((*key_arr)[i].c_str(), keylen,
|
||||||
printf("key: \t, keylen: %u\ndata: datalen: %u\n",
|
ditem.c_str(), datalen);
|
||||||
//newtuple.key,
|
|
||||||
*newtuple.keylen,
|
|
||||||
//newtuple.data,
|
|
||||||
*newtuple.datalen);
|
|
||||||
*/
|
|
||||||
|
|
||||||
datasize += newtuple.byte_length();
|
datasize += newtuple->byte_length();
|
||||||
|
|
||||||
gettimeofday(&ti_st,0);
|
gettimeofday(&ti_st,0);
|
||||||
|
|
||||||
//send the data
|
//send the data
|
||||||
// datatuple * ret = sendTuple(servername, serverport, OP_INSERT, newtuple);
|
|
||||||
datatuple * ret = logstore_client_op(l, OP_INSERT, newtuple);
|
datatuple * ret = logstore_client_op(l, OP_INSERT, newtuple);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
|
@ -158,8 +138,7 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
// insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
// insert_time += tv_to_double(ti_end) - tv_to_double(ti_st);
|
||||||
insert_time ++; // XXX
|
insert_time ++; // XXX
|
||||||
|
|
||||||
free(newtuple.key);
|
datatuple::freetuple(newtuple);
|
||||||
free(newtuple.data);
|
|
||||||
|
|
||||||
if(i % 10000 == 0 && i > 0)
|
if(i % 10000 == 0 && i > 0)
|
||||||
printf("%d / %d inserted.\n", i, NUM_ENTRIES);
|
printf("%d / %d inserted.\n", i, NUM_ENTRIES);
|
||||||
|
@ -180,53 +159,37 @@ void insertProbeIter(size_t NUM_ENTRIES)
|
||||||
{
|
{
|
||||||
int ri = i;
|
int ri = i;
|
||||||
//printf("key index%d\n", i);
|
//printf("key index%d\n", i);
|
||||||
fflush(stdout);
|
//fflush(stdout);
|
||||||
|
|
||||||
//get the key
|
//get the key
|
||||||
uint32_t keylen = (*key_arr)[ri].length()+1;
|
datatuple::len_t keylen = (*key_arr)[ri].length()+1;
|
||||||
datatuple searchtuple;
|
datatuple::len_t datalen = 0;
|
||||||
searchtuple.keylen = (uint32_t*)malloc(2*sizeof(uint32_t) + keylen);
|
|
||||||
*searchtuple.keylen = keylen;
|
|
||||||
|
|
||||||
searchtuple.datalen = searchtuple.keylen + 1;
|
datatuple* searchtuple = datatuple::create((*key_arr)[ri].c_str(), keylen);
|
||||||
*searchtuple.datalen = 0;
|
|
||||||
|
|
||||||
searchtuple.key = (datatuple::key_t)(searchtuple.keylen + 2);
|
|
||||||
memcpy((byte*)searchtuple.key, (*key_arr)[ri].c_str(), keylen);
|
|
||||||
|
|
||||||
//find the key with the given tuple
|
//find the key with the given tuple
|
||||||
datatuple *dt = logstore_client_op(l, OP_FIND, //servername, serverport, OP_FIND,
|
datatuple *dt = logstore_client_op(l, OP_FIND, searchtuple);
|
||||||
searchtuple);
|
|
||||||
|
|
||||||
assert(dt!=0);
|
assert(dt!=0);
|
||||||
assert(!dt->isDelete());
|
assert(!dt->isDelete());
|
||||||
found_tuples++;
|
found_tuples++;
|
||||||
assert(*(dt->keylen) == (*key_arr)[ri].length()+1);
|
assert(dt->keylen() == (*key_arr)[ri].length()+1);
|
||||||
|
|
||||||
//free dt
|
//free dt
|
||||||
free(dt->keylen);
|
datatuple::freetuple(dt);
|
||||||
free(dt->datalen);
|
|
||||||
free(dt->key);
|
|
||||||
free(dt->data);
|
|
||||||
free(dt);
|
|
||||||
|
|
||||||
dt = 0;
|
dt = 0;
|
||||||
|
|
||||||
free(searchtuple.keylen);
|
datatuple::freetuple(searchtuple);
|
||||||
|
|
||||||
}
|
}
|
||||||
printf("found %d\n", found_tuples);
|
printf("found %d\n", found_tuples);
|
||||||
|
|
||||||
key_arr->clear();
|
key_arr->clear();
|
||||||
//data_arr->clear();
|
|
||||||
delete key_arr;
|
delete key_arr;
|
||||||
//delete data_arr;
|
|
||||||
|
|
||||||
logstore_client_close(l);
|
logstore_client_close(l);
|
||||||
|
|
||||||
gettimeofday(&stop_tv,0);
|
gettimeofday(&stop_tv,0);
|
||||||
printf("run time: %6.1f\n", -1.0); // XXX (tv_to_double(stop_tv) - tv_to_double(start_tv)));
|
printf("run time: %6.1f\n", -1.0); // XXX (tv_to_double(stop_tv) - tv_to_double(start_tv)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "tuplemerger.h"
|
#include "tuplemerger.h"
|
||||||
#include "logstore.h"
|
#include "logstore.h"
|
||||||
|
|
||||||
|
// XXX make the imputs 'const'
|
||||||
|
// XXX test / reason about this...
|
||||||
datatuple* tuplemerger::merge(datatuple *t1, datatuple *t2)
|
datatuple* tuplemerger::merge(datatuple *t1, datatuple *t2)
|
||||||
{
|
{
|
||||||
assert(!t1->isDelete() || !t2->isDelete()); //both cannot be delete
|
assert(!t1->isDelete() || !t2->isDelete()); //both cannot be delete
|
||||||
|
@ -9,11 +11,11 @@ datatuple* tuplemerger::merge(datatuple *t1, datatuple *t2)
|
||||||
|
|
||||||
if(t1->isDelete()) //delete - t2
|
if(t1->isDelete()) //delete - t2
|
||||||
{
|
{
|
||||||
t = datatuple::from_bytes(t2->to_bytes());
|
t = t2->create_copy();
|
||||||
}
|
}
|
||||||
else if(t2->isDelete())
|
else if(t2->isDelete())
|
||||||
{
|
{
|
||||||
t = datatuple::from_bytes(t2->to_bytes());
|
t = t2->create_copy();
|
||||||
}
|
}
|
||||||
else //neither is a delete
|
else //neither is a delete
|
||||||
{
|
{
|
||||||
|
@ -32,26 +34,15 @@ datatuple* tuplemerger::merge(datatuple *t1, datatuple *t2)
|
||||||
**/
|
**/
|
||||||
datatuple* append_merger(datatuple *t1, datatuple *t2)
|
datatuple* append_merger(datatuple *t1, datatuple *t2)
|
||||||
{
|
{
|
||||||
static const size_t isize = sizeof(uint32_t);
|
|
||||||
struct datatuple *t = (datatuple*) malloc(sizeof(datatuple));
|
|
||||||
|
|
||||||
byte *arr = (byte*)malloc(t1->byte_length() + *t2->datalen);
|
assert(!(t1->isDelete() || t2->isDelete()));
|
||||||
|
datatuple::len_t keylen = t1->keylen();
|
||||||
t->keylen = (uint32_t*) arr;
|
datatuple::len_t datalen = t1->datalen() + t2->datalen();
|
||||||
*(t->keylen) = *(t1->keylen);
|
byte * data = (byte*)malloc(datalen);
|
||||||
|
memcpy(data, t1->data(), t1->datalen());
|
||||||
t->datalen = (uint32_t*) (arr+isize);
|
memcpy(data + t1->datalen(), t2->data(), t2->datalen());
|
||||||
*(t->datalen) = *(t1->datalen) + *(t2->datalen);
|
|
||||||
|
|
||||||
t->key = (datatuple::key_t) (arr+isize+isize);
|
|
||||||
memcpy((byte*)t->key, (byte*)t1->key, *(t1->keylen));
|
|
||||||
|
|
||||||
t->data = (datatuple::data_t) (arr+isize+isize+ *(t1->keylen));
|
|
||||||
memcpy((byte*)t->data, (byte*)t1->data, *(t1->datalen));
|
|
||||||
memcpy(((byte*)t->data) + *(t1->datalen), (byte*)t2->data, *(t2->datalen));
|
|
||||||
|
|
||||||
return t;
|
|
||||||
|
|
||||||
|
return datatuple::create(t1->key(), keylen, data, datalen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,23 +53,5 @@ datatuple* append_merger(datatuple *t1, datatuple *t2)
|
||||||
**/
|
**/
|
||||||
datatuple* replace_merger(datatuple *t1, datatuple *t2)
|
datatuple* replace_merger(datatuple *t1, datatuple *t2)
|
||||||
{
|
{
|
||||||
static const size_t isize = sizeof(uint32_t);
|
return t2->create_copy();
|
||||||
struct datatuple *t = (datatuple*) malloc(sizeof(datatuple));
|
|
||||||
|
|
||||||
byte *arr = (byte*)malloc(t2->byte_length());
|
|
||||||
|
|
||||||
t->keylen = (uint32_t*) arr;
|
|
||||||
*(t->keylen) = *(t2->keylen);
|
|
||||||
|
|
||||||
t->datalen = (uint32_t*) (arr+isize);
|
|
||||||
*(t->datalen) = *(t2->datalen);
|
|
||||||
|
|
||||||
t->key = (datatuple::key_t) (arr+isize+isize);
|
|
||||||
memcpy((byte*)t->key, (byte*)t2->key, *(t2->keylen));
|
|
||||||
|
|
||||||
t->data = (datatuple::data_t) (arr+isize+isize+ *(t2->keylen));
|
|
||||||
memcpy((byte*)t->data, (byte*)t2->data, *(t2->datalen));
|
|
||||||
|
|
||||||
return t;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue