diff --git a/benchmarks/roseTable.cpp b/benchmarks/roseTable.cpp index d97be3e..fb1d9d7 100644 --- a/benchmarks/roseTable.cpp +++ b/benchmarks/roseTable.cpp @@ -1,17 +1,17 @@ #include +#include #include #include "stasis/operations/lsmTable.h" #include "stasis/transactional.h" #include "stasis/page/compression/multicolumn-impl.h" +#include "stasis/page/compression/staticMulticolumn.h" #include "stasis/page/compression/for-impl.h" #include "stasis/page/compression/rle-impl.h" #include "stasis/page/compression/staticTuple.h" #include "stasis/page/compression/pageLayout.h" -typedef int32_t val_t; // XXX want multiple types! - namespace rose { template int main(int argc, char **argv) { @@ -22,7 +22,7 @@ namespace rose { unlink("logfile.txt"); sync(); - stasis_page_impl_register(Multicolumn::impl()); + stasis_page_impl_register(PAGELAYOUT::FMT::impl()); bufferManagerNonBlockingSlowHandleType = IO_HANDLE_PFILE; Tinit(); @@ -37,8 +37,12 @@ namespace rose { typename PAGELAYOUT::FMT::TUP t; - - static const long INSERTS = 10000000; + long INSERTS; + if(argc == 2) { + INSERTS = atoll(argv[1]); + } else { + INSERTS = 10 * 1000 * 1000; + } // static const long INSERTS = 10000000; // static const long INSERTS = 100000; static const long COUNT = INSERTS / 100; @@ -51,13 +55,24 @@ namespace rose { start = rose::tv_to_double(start_tv); last_start = start; - printf("tuple 'size'%d\n", PAGELAYOUT::FMT::TUP::sizeofBytes()); + printf("tuple 'size'%d ; %d\n", PAGELAYOUT::FMT::TUP::sizeofBytes(), sizeof(typename PAGELAYOUT::FMT::TUP)); for(long int i = 0; i < INSERTS; i++) { - t.set0(&i); - t.set1(&i); - t.set2(&i); - t.set3(&i); + typename PAGELAYOUT::FMT::TUP::TYP0 m = i;// % 65536; + typename PAGELAYOUT::FMT::TUP::TYP1 j = 0 / 65536; + typename PAGELAYOUT::FMT::TUP::TYP2 k = 0 / 12514500; + typename PAGELAYOUT::FMT::TUP::TYP3 l = 0 / 10000000; + + t.set0(&m); + t.set1(&l); + t.set2(&l); + t.set3(&l); + t.set4(&l); + t.set5(&l); + t.set6(&l); + t.set7(&l); + t.set8(&l); + t.set9(&l); TlsmTableInsert(h,t); count --; if(!count) { @@ -85,12 +100,43 @@ namespace rose { } int main(int argc, char **argv) { - // typedef rose::StaticTuple<4,int64_t,int32_t,int16_t,int8_t> tup; - typedef rose::StaticTuple<4,int64_t,int64_t,int64_t,int64_t> tup; - // XXX multicolumn is deprecated; want static dispatch! - return rose::main + + typedef int64_t typ0; + typedef int64_t typ1; + typedef int64_t typ2; + typedef int64_t typ3; + typedef int64_t typ4; + typedef int64_t typ5; + typedef int64_t typ6; + typedef int64_t typ7; + typedef int64_t typ8; + typedef int64_t typ9; + + #define COLS 10 + + typedef rose::StaticTuple tup; + using rose::For; + using rose::Rle; + + // multicolumn is deprecated; want static dispatch! + + /* return rose::main ,rose::For > > + (argc,argv); */ + + return rose::main + ,Rle, + Rle,Rle, + Rle,Rle, + Rle,Rle, + Rle,Rle > + > + > (argc,argv); + return 0; } diff --git a/src/stasis/operations/lsmTable.h b/src/stasis/operations/lsmTable.h index a1e279a..cb111cb 100644 --- a/src/stasis/operations/lsmTable.h +++ b/src/stasis/operations/lsmTable.h @@ -328,8 +328,8 @@ namespace rose { static const int RB_TREE_OVERHEAD = 450; static const pageid_t MEM_SIZE = 800 * 1000 * 1000; // How many pages should we try to fill with the first C1 merge? - static const pageid_t START_SIZE = 10 * 1000; - static const int R = 40; + static const pageid_t START_SIZE = /*10 **/ 1000; + static const int R = 10; // XXX set this as low as possible (for dynamic setting. = sqrt(C2 size / C0 size)) template lsmTableHandle * TlsmTableStart(recordid& tree) { @@ -444,7 +444,7 @@ namespace rose { ret->still_open, block0_size, block1_size, - (R * MEM_SIZE) / (PAGE_SIZE * 4), // 4 = estimated compression ratio + (R * MEM_SIZE) / (PAGE_SIZE * 4), // XXX 4 = estimated compression ratio R, new typename LSM_ITER::treeIteratorHandle(NULLRID), block0_scratch, diff --git a/src/stasis/page/compression/multicolumn-impl.h b/src/stasis/page/compression/multicolumn-impl.h index cd91229..30dad2a 100644 --- a/src/stasis/page/compression/multicolumn-impl.h +++ b/src/stasis/page/compression/multicolumn-impl.h @@ -36,11 +36,6 @@ Multicolumn::Multicolumn(int xid, Page *p, column_number_t column_count, p->impl = this; } -/** - XXX this eagerly unpacks the page at load; that's a waste of - processor time and RAM, as read-only pages don't need to be - unpacked. -*/ template Multicolumn::Multicolumn(Page * p) : p_(p), @@ -68,7 +63,7 @@ Multicolumn::Multicolumn(Page * p) : bytes_left_ = *exceptions_offset_ptr() - first_free; - assert(*stasis_page_type_ptr(p) == Multicolumn::plugin_id()); + assert(*stasis_page_type_ptr(p) == (Multicolumn::plugin_id())); } template diff --git a/src/stasis/page/compression/multicolumn.h b/src/stasis/page/compression/multicolumn.h index 9621db0..3b40ddc 100644 --- a/src/stasis/page/compression/multicolumn.h +++ b/src/stasis/page/compression/multicolumn.h @@ -6,7 +6,8 @@ #include #include -#include "pstar.h" // for typedefs + consts (XXX add new header?) +#include "compression.h" +//#include "pstar.h" // for typedefs + consts (XXX add new header?) #include "tuple.h" // XXX rename tuple.hx #include "pluginDispatcher.h" // Copyright 2007 Google Inc. All Rights Reserved. diff --git a/src/stasis/page/compression/pageLayout.h b/src/stasis/page/compression/pageLayout.h index 88a263d..e5f870b 100644 --- a/src/stasis/page/compression/pageLayout.h +++ b/src/stasis/page/compression/pageLayout.h @@ -59,5 +59,89 @@ namespace rose { template recordid TlsmTableAlloc(); + //// --- multicolumn static page layout + + template + class MultiColumnTypePageLayout { + public: + typedef FORMAT FMT; + static inline void initPageLayout() { + stasis_page_impl_register(FMT::impl()); + + // XXX these should register template instantiations of worker + // threads that are statically compiled to deal with the tree + // we're instantiating. + lsmTreeRegisterComparator(cmp_num, FMT::TUP::cmp); + lsmTreeRegisterPageInitializer + (init_num, (lsm_page_initializer_t)initPage); + my_cmp_num = cmp_num; + cmp_num++; + my_init_num = init_num; + init_num++; + } + static inline FORMAT * initPage(Page *p, const typename FORMAT::TUP * t) { + const column_number_t column_count = t->column_count(); + + //plugin_id_t pluginid = plugin_id(); + + plugin_id_t plugins[N]; + if(0 < N) plugins[0] = plugin_id(); + if(1 < N) plugins[1] = plugin_id(); + if(2 < N) plugins[2] = plugin_id(); + if(3 < N) plugins[3] = plugin_id(); + if(4 < N) plugins[4] = plugin_id(); + if(5 < N) plugins[5] = plugin_id(); + if(6 < N) plugins[6] = plugin_id(); + if(7 < N) plugins[7] = plugin_id(); + if(8 < N) plugins[8] = plugin_id(); + if(9 < N) plugins[9] = plugin_id(); + + FORMAT * f = new FORMAT(-1,p);//N,plugins); + + //plugin_id_t * plugins = (plugin_id_t*)malloc(column_count * sizeof(plugin_id_t)); + //for(column_number_t c = 0; c < column_count; c++) { + //plugins[c] = pluginid; + //} + // FORMAT * f = new FORMAT(-1,p,column_count,plugins); + + if(0 < N) f->compressor0()->offset(*t->get0()); + if(1 < N) f->compressor1()->offset(*t->get1()); + if(2 < N) f->compressor2()->offset(*t->get2()); + if(3 < N) f->compressor3()->offset(*t->get3()); + if(4 < N) f->compressor4()->offset(*t->get4()); + if(5 < N) f->compressor5()->offset(*t->get5()); + if(6 < N) f->compressor6()->offset(*t->get6()); + if(7 < N) f->compressor7()->offset(*t->get7()); + if(8 < N) f->compressor8()->offset(*t->get8()); + if(9 < N) f->compressor9()->offset(*t->get9()); + + /*for(column_number_t c = 0; c < column_count; c++) { + COMPRESSOR* com = (COMPRESSOR*) f->compressor(c); + typename COMPRESSOR::TYP val = *(typename COMPRESSOR::TYP*)(t->get(c)); + com->offset(val); + }*/ + // free(plugins); + return f; + } + static inline int cmp_id() { + return my_cmp_num; + } + static inline int init_id() { + return my_init_num; + } + private: + static int my_cmp_num; + static int my_init_num; + }; + template + int MultiColumnTypePageLayout::my_cmp_num = -1; + template + int MultiColumnTypePageLayout::my_init_num = -1; + + template + recordid TlsmTableAlloc(); + + + } #endif // _ROSE_COMPRESSION_PAGELAYOUT_H__ diff --git a/src/stasis/page/compression/staticMulticolumn.h b/src/stasis/page/compression/staticMulticolumn.h new file mode 100644 index 0000000..36177b8 --- /dev/null +++ b/src/stasis/page/compression/staticMulticolumn.h @@ -0,0 +1,455 @@ +#ifndef _ROSE_COMPRESSION_STATIC_MULTICOLUMN_H__ +#define _ROSE_COMPRESSION_STATIC_MULTICOLUMN_H__ + +#include + +#include +#include +#include + +#include "compression.h" + +//#include "pstar.h" // for typedefs + consts (XXX add new header?) +#include "tuple.h" // XXX rename tuple.hx +//#include "pluginDispatcher.h" +// Copyright 2007 Google Inc. All Rights Reserved. +// Author: sears@google.com (Rusty Sears) + +/** + @file Page implementation for multi-column, compressed data + + STRUCTURE OF A MULTICOLUMN PAGE + +
+ +----------------------------------------------------------------------+
+ | col #0 compressed data (opaque) | col #1 compressed data (opaque)    |
+ +-----+---------------------------+-----+------------------------------|
+ | ... | col #N compressed data (opaque) |                              |
+ +-----+---------------------------------+                              |
+ |  Free space                                                          |
+ |                                                                      |
+ |                                                                      |
+ |                             +----------------------------------------+
+ |                             | Exceptions:                            |
+ +-----------------------------+ Includes data from multiple cols       |
+ |                                                                      |
+ | Exception data is managed (bytes are copied in and out of this       |
+ | region) by the column implementations.  Multicolumn mediates between |
+ | the columns, by recording the length and offset of this region.      |
+ |                                                                      |
+ |                                      +---------------+---------------+
+ |                                  ... | exception # 1 | exception # 0 |
+ +-----------------------+--------------------+----+--------------------+
+ |  first header byte -> | col #N off, plugin | .. | col #1 off, plugin |
+ +--------------------+--+-------------+------+----+----+-----------+---+
+ | col #0 off, plugin | exceptions len | exceptions off | # of cols | ? |
+ +--------------------+----------------+----------------+-----------+---+
+
+ + Notes: + + The 'exceptions' portion of the page grows down from + first_header_byte, while the column data portion grows up from byte + zero... This was an arbitrary decision, and complicated the + implementation somewhat... + + Functions whose names end in "_ptr" return pointers to bytes in the + page. That memory is persistant; and will eventually be written + back to the page file. + +*/ + +namespace rose { + +/** + * A "pageLoaded()" callback function for Stasis' buffer manager. + */ +template +void staticMulticolumnLoaded(Page *p); + +template , class COMP2 = For, + class COMP3=For, class COMP4=For, class COMP5=For, + class COMP6=For, class COMP7=For, class COMP8=For, + class COMP9=For > +class StaticMulticolumn { + public: + static page_impl impl(); + static const plugin_id_t PAGE_FORMAT_ID = 1; + typedef TUPLE TUP; + + typedef COMP0 CMP0; + typedef COMP1 CMP1; + typedef COMP2 CMP2; + typedef COMP3 CMP3; + typedef COMP4 CMP4; + typedef COMP5 CMP5; + typedef COMP6 CMP6; + typedef COMP7 CMP7; + typedef COMP8 CMP8; + typedef COMP9 CMP9; + + StaticMulticolumn(int xid, Page *p) : + p_(p), + first_exception_byte_(USABLE_SIZE_OF_PAGE), + exceptions_(new byte[USABLE_SIZE_OF_PAGE]), + unpacked_(1) +{ + + *column_count_ptr() = N; + + bytes_left_ = first_header_byte_ptr()- p->memAddr; + + /* for(int i = 0; i < N; i++) { + *column_plugin_id_ptr(i) = plugins[i]; + dispatcher_.set_plugin(columns_[i],i,plugins[i]); + dispatcher_.init_mem(columns_[i],i); + bytes_left_ -= dispatcher_.bytes_used(i); + } */ + +#define STATIC_MC_INIT(i,typ,cmp) \ + if(i < N) { \ + *column_plugin_id_ptr(i) = cmp->PLUGIN_ID; \ + columns_[i] = new byte[USABLE_SIZE_OF_PAGE]; \ + /* if(plugin0) delete plugin0; */ \ + cmp = new typ(xid,columns_[i]); \ + cmp->init_mem(columns_[i]); \ + bytes_left_ -= cmp->bytes_used(); \ + } + + STATIC_MC_INIT(0, CMP0, plugin0) STATIC_MC_INIT(1, CMP1, plugin1) STATIC_MC_INIT(2, CMP2, plugin2) ; + STATIC_MC_INIT(3, CMP3, plugin3) STATIC_MC_INIT(4, CMP4, plugin4) STATIC_MC_INIT(5, CMP5, plugin5) ; + STATIC_MC_INIT(6, CMP6, plugin6) STATIC_MC_INIT(7, CMP7, plugin7) STATIC_MC_INIT(8, CMP8, plugin8) ; + STATIC_MC_INIT(9, CMP9, plugin9); + +#undef STATIC_MC_INIT + + *stasis_page_type_ptr(p) = plugin_id(); + p->impl = this; +} + + ~StaticMulticolumn() { + byte_off_t first_free = 0; + byte_off_t last_free = (intptr_t)(first_header_byte_ptr() - p_->memAddr); + if(unpacked_) { + *exceptions_len_ptr() = USABLE_SIZE_OF_PAGE - first_exception_byte_; + last_free -= *exceptions_len_ptr(); + + *exceptions_offset_ptr() = last_free; + memcpy(&(p_->memAddr[*exceptions_offset_ptr()]), + exceptions_ + first_exception_byte_, *exceptions_len_ptr()); + +#define STATIC_MC_DEINIT(i,plug) \ + if(i < N) { \ + *column_offset_ptr(i) = first_free; \ + byte_off_t bytes_used = plug->bytes_used(); \ + memcpy(column_base_ptr(i), columns_[i], bytes_used); \ + first_free += bytes_used; \ + assert(first_free <= last_free); \ + delete [] columns_[i]; \ + } + + STATIC_MC_DEINIT(0,plugin0); + STATIC_MC_DEINIT(1,plugin1); + STATIC_MC_DEINIT(2,plugin2); + STATIC_MC_DEINIT(3,plugin3); + STATIC_MC_DEINIT(4,plugin4); + STATIC_MC_DEINIT(5,plugin5); + STATIC_MC_DEINIT(6,plugin6); + STATIC_MC_DEINIT(7,plugin7); + STATIC_MC_DEINIT(8,plugin8); + STATIC_MC_DEINIT(9,plugin9); + + delete [] exceptions_; + } + } + + /** + @return the compressor used for a column. The nature of the + mapping between table region and compressor instance is + implementation defined, but there will never be more than one + compressor per-column, per-page. + + @param col The column whose compressor should be returned. + @return A pointer to a compressor. This pointer is guaranteed to + be valid until the next call to this Multicolumn object. After + that, the pointer returned here is invalid. + */ + // void* compressor(column_number_t col) { + // XXX return dispatcher_.compressor(col); + // } + COMP0 * compressor0() const { return plugin0; } + COMP1 * compressor1() const { return plugin1; } + COMP2 * compressor2() const { return plugin2; } + COMP3 * compressor3() const { return plugin3; } + COMP4 * compressor4() const { return plugin4; } + COMP5 * compressor5() const { return plugin5; } + COMP6 * compressor6() const { return plugin6; } + COMP7 * compressor7() const { return plugin7; } + COMP8 * compressor8() const { return plugin8; } + COMP9 * compressor9() const { return plugin9; } + + inline slot_index_t append(int xid, TUPLE const & dat) { + slot_index_t ret = 0; + if(0 < N) ret = plugin0->append(xid, *dat.get0(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(1 < N) ret = plugin1->append(xid, *dat.get1(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(2 < N) ret = plugin2->append(xid, *dat.get2(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(3 < N) ret = plugin3->append(xid, *dat.get3(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(4 < N) ret = plugin4->append(xid, *dat.get4(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(5 < N) ret = plugin5->append(xid, *dat.get5(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(6 < N) ret = plugin6->append(xid, *dat.get6(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(7 < N) ret = plugin7->append(xid, *dat.get7(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(8 < N) ret = plugin8->append(xid, *dat.get8(),&first_exception_byte_, + exceptions_, &bytes_left_); + if(9 < N) ret = plugin9->append(xid, *dat.get9(),&first_exception_byte_, + exceptions_, &bytes_left_); + return bytes_left_ < 0 ? NOSPACE : ret; + } + inline TUPLE * recordRead(int xid, slot_index_t slot, TUPLE * buf) { + bool ret = 1; + if(0 < N) ret = plugin0->recordRead(xid,slot,exceptions_,const_cast(buf->get0())) ? ret : 0; + if(1 < N) ret = plugin1->recordRead(xid,slot,exceptions_,const_cast(buf->get1())) ? ret : 0; + if(2 < N) ret = plugin2->recordRead(xid,slot,exceptions_,const_cast(buf->get2())) ? ret : 0; + if(3 < N) ret = plugin3->recordRead(xid,slot,exceptions_,const_cast(buf->get3())) ? ret : 0; + if(4 < N) ret = plugin4->recordRead(xid,slot,exceptions_,const_cast(buf->get4())) ? ret : 0; + if(5 < N) ret = plugin5->recordRead(xid,slot,exceptions_,const_cast(buf->get5())) ? ret : 0; + if(6 < N) ret = plugin6->recordRead(xid,slot,exceptions_,const_cast(buf->get6())) ? ret : 0; + if(7 < N) ret = plugin7->recordRead(xid,slot,exceptions_,const_cast(buf->get7())) ? ret : 0; + if(8 < N) ret = plugin8->recordRead(xid,slot,exceptions_,const_cast(buf->get8())) ? ret : 0; + if(9 < N) ret = plugin9->recordRead(xid,slot,exceptions_,const_cast(buf->get9())) ? ret : 0; + return ret ? buf : 0; + } + inline void pack() { + byte_off_t first_free = 0; + byte_off_t last_free = (intptr_t)(first_header_byte_ptr() - p_->memAddr); + if(unpacked_) { + *exceptions_len_ptr() = USABLE_SIZE_OF_PAGE - first_exception_byte_; + last_free -= *exceptions_len_ptr(); + + *exceptions_offset_ptr() = last_free; + memcpy(&(p_->memAddr[*exceptions_offset_ptr()]), + exceptions_ + first_exception_byte_, *exceptions_len_ptr()); + +#define STATIC_MC_PACK(i,comp) \ + if(i < N) { \ + *column_offset_ptr(i) = first_free; \ + byte_off_t bytes_used = comp->bytes_used(); \ + memcpy(column_base_ptr(i), columns_[i], bytes_used); \ + first_free += bytes_used; \ + assert(first_free <= last_free); \ + delete [] columns_[i]; \ + columns_[i] = column_base_ptr(i); \ + comp->mem(columns_[i]); \ + } + + STATIC_MC_PACK(0,plugin0) STATIC_MC_PACK(1,plugin1) ; + STATIC_MC_PACK(2,plugin2) STATIC_MC_PACK(3,plugin3) ; + STATIC_MC_PACK(4,plugin4) STATIC_MC_PACK(5,plugin5) ; + STATIC_MC_PACK(6,plugin6) STATIC_MC_PACK(7,plugin7) ; + STATIC_MC_PACK(8,plugin8) STATIC_MC_PACK(9,plugin9) ; + +#undef STATIC_MC_PACK + + delete [] exceptions_; + exceptions_ = p_->memAddr + *exceptions_offset_ptr(); + unpacked_ = 0; + } + } + private: + COMP0* plugin0; COMP1* plugin1; COMP2* plugin2; COMP3* plugin3; + COMP4* plugin4; COMP5* plugin5; COMP6* plugin6; COMP7* plugin7; + COMP8* plugin8; COMP9* plugin9; + + typedef struct column_header { + byte_off_t off; + plugin_id_t plugin_id; + } column_header; + + /** + Load an existing multicolumn Page + */ + StaticMulticolumn(Page * p) : + p_(p), + first_exception_byte_(USABLE_SIZE_OF_PAGE - *exceptions_len_ptr()), + exceptions_(p_->memAddr + *exceptions_offset_ptr()), + unpacked_(0) { + byte_off_t first_free = 0; + assert(N == *column_count_ptr()); + +#define STATIC_MC_INIT(i,plug,cmp) \ + if(i < N) { \ + /*byte * page_column_ptr = p_->memAddr + *column_offset_ptr(i);*/ \ + columns_[i] = p_->memAddr + *column_offset_ptr(i); \ + plug = new cmp((void*)columns_[i]); \ + first_free = *column_offset_ptr(i) + plug->bytes_used(); \ + } + + STATIC_MC_INIT(0, plugin0,COMP0) ; + STATIC_MC_INIT(1, plugin1,COMP1) ; + STATIC_MC_INIT(2, plugin2,COMP2) ; + STATIC_MC_INIT(3, plugin3,COMP3) ; + STATIC_MC_INIT(4, plugin4,COMP4) ; + STATIC_MC_INIT(5, plugin5,COMP5) ; + STATIC_MC_INIT(6, plugin6,COMP6) ; + STATIC_MC_INIT(7, plugin7,COMP7) ; + STATIC_MC_INIT(8, plugin8,COMP8) ; + STATIC_MC_INIT(9, plugin9,COMP9) ; + +#undef STATIC_MC_INIT + + assert(first_free <= *exceptions_offset_ptr()); + assert(first_exception_byte_ <= USABLE_SIZE_OF_PAGE); + + bytes_left_ = *exceptions_offset_ptr() - first_free; + + assert(*stasis_page_type_ptr(p) == (plugin_id())); + } + + /** + The following functions perform pointer arithmetic. This code is + performance critical. These short, inlined functions mostly + perform simple arithmetic expression involving constants. g++'s + optimizer seems to combine and simplify these expressions for us. + + See the page layout diagram at the top of this file for an + explanation of where these pointers are stored + */ + + inline column_number_t * column_count_ptr() { + return reinterpret_cast(p_->memAddr+USABLE_SIZE_OF_PAGE)-1; + } + inline byte_off_t * exceptions_offset_ptr() { + return reinterpret_cast(column_count_ptr())-1; + } + inline byte_off_t * exceptions_len_ptr() { + return exceptions_offset_ptr()-1;; + } + inline column_header * column_header_ptr(column_number_t column_number) { + return reinterpret_cast(exceptions_len_ptr())-(1+column_number); + } + inline byte_off_t * column_offset_ptr(column_number_t column_number) { + return &(column_header_ptr(column_number)->off); + } + /** + This stores the plugin_id associated with this page's compressor. + + @see rose::plugin_id() + */ + inline plugin_id_t * column_plugin_id_ptr(column_number_t column_number) { + return &(column_header_ptr(column_number)->plugin_id); + } + /** + The first byte that contains data for this column. + + The length of the column data can be determined by calling + COMPRESSOR's bytes_used() member function. (PluginDispatcher + can handle this). + */ + inline byte * column_base_ptr(column_number_t column_number) { + return *column_offset_ptr(column_number) + p_->memAddr; + } + inline byte * first_header_byte_ptr() { + return reinterpret_cast(column_header_ptr((*column_count_ptr())-1)); + } + + static inline plugin_id_t plugin_id() { + // XXX collides with multicolumn.h + return USER_DEFINED_PAGE(0) + 32 + TUPLE::TUPLE_ID; + } + Page * p_; + byte * columns_[N]; + byte_off_t first_exception_byte_; + byte * exceptions_; + int bytes_left_; + int unpacked_; + friend void staticMulticolumnLoaded(Page *p); +}; + + +/// End performance-critical code --------------------------------------------- + +/// Stuff below this line interfaces with Stasis' buffer manager -------------- + +/** + Basic page_impl for multicolumn pages + + @see stasis/page.h and pstar-impl.h + +*/ +static const page_impl static_multicolumn_impl = { + -1, + 0, // multicolumnRead, + 0, // multicolumnWrite, + 0, // multicolumnReadDone, + 0, // multicolumnWriteDone, + 0, // multicolumnGetType, + 0, // multicolumnSetType, + 0, // multicolumnGetLength, + 0, // multicolumnFirst, + 0, // multicolumnNext, + 0, // multicolumnIsBlockSupported, + 0, // multicolumnBlockFirst, + 0, // multicolumnBlockNext, + 0, // multicolumnBlockDone, + 0, // multicolumnFreespace, + 0, // multicolumnCompact, + 0, // multicolumnPreRalloc, + 0, // multicolumnPostRalloc, + 0, // multicolumnFree, + 0, // dereference_identity, + 0, // multicolumnLoaded, + 0, // multicolumnFlushed + 0, // multicolumnCleanup +}; + +template +void staticMulticolumnLoaded(Page *p) { + p->LSN = *stasis_page_lsn_ptr(p); + assert(*stasis_page_type_ptr(p) == (StaticMulticolumn::plugin_id())); + p->impl = new StaticMulticolumn(p); +} +template +static void staticMulticolumnFlushed(Page *p) { + *stasis_page_lsn_ptr(p) = p->LSN; + ((StaticMulticolumn*)(p->impl))->pack(); +} +template +static void staticMulticolumnCleanup(Page *p) { + delete (StaticMulticolumn*)p->impl; + p->impl = 0; +} + +template +page_impl StaticMulticolumn::impl() { + page_impl ret = static_multicolumn_impl; + ret.page_type = StaticMulticolumn::plugin_id(); + ret.pageLoaded = staticMulticolumnLoaded; + ret.pageFlushed = staticMulticolumnFlushed; + ret.pageCleanup = staticMulticolumnCleanup; + return ret; +} + + + +} // namespace rose + + +#endif // _ROSE_COMPRESSION_STATIC_MULTICOLUMN_H__ diff --git a/src/stasis/page/compression/staticTuple.h b/src/stasis/page/compression/staticTuple.h index f961f12..f3c6ae5 100644 --- a/src/stasis/page/compression/staticTuple.h +++ b/src/stasis/page/compression/staticTuple.h @@ -2,7 +2,6 @@ #define _ROSE_COMPRESSION_STATICTUPLE_H__ namespace rose { - template + short StaticTuple::cols_[N]; + template + byte_off_t StaticTuple::size_[N]; + template + bool StaticTuple::first_ = true; +} #endif // _ROSE_COMPRESSION_STATICTUPLE_H__