add latch-free slotted pages, and a bug-fix in page.c
This commit is contained in:
parent
e6067ae60b
commit
bb904e85cf
9 changed files with 247 additions and 7 deletions
|
@ -24,6 +24,7 @@ ADD_LIBRARY(stasis crc32.c redblack.c tsearchcompat.c lhtable.c concurrentHash.c
|
||||||
page/raw.c
|
page/raw.c
|
||||||
page/lsnFree.c
|
page/lsnFree.c
|
||||||
page/segment.c
|
page/segment.c
|
||||||
|
page/latchFree/lfSlotted.c
|
||||||
compensations.c
|
compensations.c
|
||||||
operations/pageOperations.c
|
operations/pageOperations.c
|
||||||
operations/decrement.c operations/increment.c
|
operations/decrement.c operations/increment.c
|
||||||
|
|
|
@ -77,6 +77,7 @@ terms specified in this license.
|
||||||
#include <stasis/page/slotted.h>
|
#include <stasis/page/slotted.h>
|
||||||
#include <stasis/page/fixed.h>
|
#include <stasis/page/fixed.h>
|
||||||
#include <stasis/page/uninitialized.h>
|
#include <stasis/page/uninitialized.h>
|
||||||
|
#include <stasis/page/latchFree/lfSlotted.h>
|
||||||
#include <stasis/operations/arrayList.h>
|
#include <stasis/operations/arrayList.h>
|
||||||
#include <stasis/bufferPool.h>
|
#include <stasis/bufferPool.h>
|
||||||
#include <stasis/truncation.h>
|
#include <stasis/truncation.h>
|
||||||
|
@ -120,6 +121,7 @@ void stasis_page_init(stasis_dirty_page_table_t * dpt) {
|
||||||
stasis_page_impl_register(lsmRootImpl());
|
stasis_page_impl_register(lsmRootImpl());
|
||||||
stasis_page_impl_register(slottedLsnFreeImpl());
|
stasis_page_impl_register(slottedLsnFreeImpl());
|
||||||
stasis_page_impl_register(segmentImpl());
|
stasis_page_impl_register(segmentImpl());
|
||||||
|
stasis_page_impl_register(stasis_page_slotted_latch_free_impl());
|
||||||
}
|
}
|
||||||
|
|
||||||
void stasis_page_deinit() {
|
void stasis_page_deinit() {
|
||||||
|
@ -147,7 +149,7 @@ void stasis_record_write(int xid, Page * p, recordid rid, const byte *dat) {
|
||||||
assert(rid.size <= BLOB_THRESHOLD_SIZE);
|
assert(rid.size <= BLOB_THRESHOLD_SIZE);
|
||||||
|
|
||||||
byte * buf = stasis_record_write_begin(xid, p, rid);
|
byte * buf = stasis_record_write_begin(xid, p, rid);
|
||||||
memcpy(buf, dat, stasis_record_length_read(xid, p, rid));
|
memcpy(buf, dat, stasis_record_type_to_size(rid.size));
|
||||||
stasis_record_write_done(xid,p,rid,buf);
|
stasis_record_write_done(xid,p,rid,buf);
|
||||||
assert( (p->id == rid.page) && (p->memAddr != NULL) );
|
assert( (p->id == rid.page) && (p->memAddr != NULL) );
|
||||||
}
|
}
|
||||||
|
@ -157,6 +159,7 @@ int stasis_record_read(int xid, Page * p, recordid rid, byte *buf) {
|
||||||
|
|
||||||
const byte * dat = stasis_record_read_begin(xid,p,rid);
|
const byte * dat = stasis_record_read_begin(xid,p,rid);
|
||||||
memcpy(buf, dat, stasis_record_length_read(xid,p,rid));
|
memcpy(buf, dat, stasis_record_length_read(xid,p,rid));
|
||||||
|
stasis_record_read_done(xid,p,rid,dat);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -182,7 +185,9 @@ const byte * stasis_record_read_begin(int xid, Page * p, recordid rid) {
|
||||||
byte * stasis_record_write_begin(int xid, Page * p, recordid rid) {
|
byte * stasis_record_write_begin(int xid, Page * p, recordid rid) {
|
||||||
int page_type = p->pageType;
|
int page_type = p->pageType;
|
||||||
assert(page_type);
|
assert(page_type);
|
||||||
assert(stasis_record_length_read(xid, p, rid) == stasis_record_type_to_size(rid.size));
|
if(p->pageType != SLOTTED_LATCH_FREE_PAGE) {
|
||||||
|
assert(stasis_record_length_read(xid, p, rid) == stasis_record_type_to_size(rid.size));
|
||||||
|
}
|
||||||
return page_impls[page_type].recordWrite(xid, p, rid);
|
return page_impls[page_type].recordWrite(xid, p, rid);
|
||||||
}
|
}
|
||||||
void stasis_record_read_done(int xid, Page *p, recordid rid, const byte *b) {
|
void stasis_record_read_done(int xid, Page *p, recordid rid, const byte *b) {
|
||||||
|
|
113
src/stasis/page/latchFree/lfSlotted.c
Normal file
113
src/stasis/page/latchFree/lfSlotted.c
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* lfSlotted.c
|
||||||
|
*
|
||||||
|
* Created on: Aug 19, 2010
|
||||||
|
* Author: sears
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stasis/common.h>
|
||||||
|
#include <stasis/page.h>
|
||||||
|
#include <stasis/page/latchFree/lfSlotted.h>
|
||||||
|
|
||||||
|
#define CAS(_a,_o,_n) __sync_bool_compare_and_swap(_a,_o,_n)
|
||||||
|
#define BARRIER() __sync_synchronize()
|
||||||
|
#define ATOMIC_ADD(_a, _i) __sync_add_and_fetch(_a, _i)
|
||||||
|
|
||||||
|
static int notSupported(int xid, Page * p) { return 0; }
|
||||||
|
|
||||||
|
static const byte* lfSlottedRead (int xid, Page *p, recordid rid) {
|
||||||
|
return stasis_page_slotted_record_cptr(p, rid.slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte* lfSlottedWrite(int xid, Page *p, recordid rid) {
|
||||||
|
assert(*stasis_page_slotted_numslots_cptr(p) == rid.slot);
|
||||||
|
return stasis_page_slotted_record_ptr(p, rid.slot);
|
||||||
|
}
|
||||||
|
static void lfSlottedWriteDone(int xid, Page *p, recordid rid, byte *buf) {
|
||||||
|
BARRIER();
|
||||||
|
int succ = CAS(stasis_page_slotted_numslots_ptr(p), rid.slot, rid.slot+1);
|
||||||
|
DEBUG("write done %d\n", rid.slot+1);
|
||||||
|
assert(succ);
|
||||||
|
}
|
||||||
|
static int lfSlottedRecordGetType(int xid, Page *p, recordid rid) {
|
||||||
|
if(*stasis_page_slotted_numslots_cptr(p) <= rid.slot) { return INVALID_SLOT; }
|
||||||
|
int ret = *stasis_page_slotted_slot_length_cptr(p, rid.slot);
|
||||||
|
return ret >= 0 ? NORMAL_SLOT : ret;
|
||||||
|
}
|
||||||
|
static int lfSlottedRecordGetLength(int xid, Page *p, recordid rid) {
|
||||||
|
if(*stasis_page_slotted_numslots_cptr(p) <= rid.slot) { return INVALID_SLOT; }
|
||||||
|
int ret = *stasis_page_slotted_slot_length_cptr(p, rid.slot);
|
||||||
|
return stasis_record_type_to_size(ret);
|
||||||
|
}
|
||||||
|
static recordid lfSlottedRecordFirst(int xid, Page *p) {
|
||||||
|
recordid ret;
|
||||||
|
ret.page = p->id;
|
||||||
|
ret.slot = 0;
|
||||||
|
ret.size = lfSlottedRecordGetType(xid, p, ret);
|
||||||
|
return ret.size == INVALID_SLOT ? NULLRID : ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
static recordid lfSlottedRecordNext(int xid, Page *p, recordid ret) {
|
||||||
|
ret.slot++;
|
||||||
|
ret.size = lfSlottedRecordGetType(xid, p, ret);
|
||||||
|
DEBUG("next %d %d %d\n", ret.slot, (int)ret.size, *stasis_page_slotted_numslots_ptr(p));
|
||||||
|
return ret.size == INVALID_SLOT ? NULLRID : ret;
|
||||||
|
}
|
||||||
|
static recordid lfSlottedRecordLast(int xid, Page *p) {
|
||||||
|
recordid ret;
|
||||||
|
ret.page = p->id;
|
||||||
|
ret.slot = (*stasis_page_slotted_numslots_cptr(p))-1;
|
||||||
|
ret.size = lfSlottedRecordGetType(xid, p, ret);
|
||||||
|
return ret.size == INVALID_SLOT ? NULLRID : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lfSlottedPostAlloc(int xid, Page * page, recordid rid) {
|
||||||
|
int16_t off = __sync_fetch_and_add(stasis_page_slotted_freespace_ptr(page), stasis_record_type_to_size(rid.size));
|
||||||
|
*stasis_page_slotted_slot_ptr(page, rid.slot) = off;
|
||||||
|
*stasis_page_slotted_slot_length_ptr(page, rid.slot) = rid.size;
|
||||||
|
// don't update numslots_ptr yet. Note that we can only have one append at a time with this update protocol...
|
||||||
|
}
|
||||||
|
void lfSlottedRecordFree(int xid, Page *p, recordid rid) {
|
||||||
|
*stasis_page_slotted_slot_length_ptr(p, rid.slot) = INVALID_SLOT;
|
||||||
|
BARRIER();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stasis_page_slotted_latch_free_initialize_page(Page * page) {
|
||||||
|
stasis_page_slotted_initialize_page(page);
|
||||||
|
page->pageType = SLOTTED_LATCH_FREE_PAGE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
page_impl stasis_page_slotted_latch_free_impl(void) {
|
||||||
|
page_impl slotted = stasis_page_slotted_impl();
|
||||||
|
page_impl pi = {
|
||||||
|
SLOTTED_LATCH_FREE_PAGE,
|
||||||
|
1,
|
||||||
|
lfSlottedRead,
|
||||||
|
lfSlottedWrite,
|
||||||
|
0,// readDone (no-op)
|
||||||
|
lfSlottedWriteDone,
|
||||||
|
lfSlottedRecordGetType,
|
||||||
|
0, // not supported
|
||||||
|
lfSlottedRecordGetLength,
|
||||||
|
lfSlottedRecordFirst,
|
||||||
|
lfSlottedRecordNext,
|
||||||
|
lfSlottedRecordLast,
|
||||||
|
notSupported, // is block supported
|
||||||
|
stasis_block_first_default_impl,
|
||||||
|
stasis_block_next_default_impl,
|
||||||
|
stasis_block_done_default_impl,
|
||||||
|
slotted.pageFreespace, // this should work as is.
|
||||||
|
NULL, // slotted.pageCompact, // there is no chance of supporting this
|
||||||
|
NULL, //slotted.pageCompactSlotIDs, // ditto
|
||||||
|
slotted.recordPreAlloc, // this is fine; it's read only...
|
||||||
|
lfSlottedPostAlloc,
|
||||||
|
0, // can't splice lots of records atomically with the current scheme.
|
||||||
|
lfSlottedRecordFree,
|
||||||
|
0, // page_impl_dereference_identity,
|
||||||
|
slotted.pageLoaded,
|
||||||
|
slotted.pageFlushed,
|
||||||
|
slotted.pageCleanup
|
||||||
|
};
|
||||||
|
return pi;
|
||||||
|
}
|
|
@ -50,7 +50,8 @@ static inline void slottedFsck(const Page const * page) {
|
||||||
assert(slotListStart < PAGE_SIZE && slotListStart >= 0);
|
assert(slotListStart < PAGE_SIZE && slotListStart >= 0);
|
||||||
assert(page_type == SLOTTED_PAGE ||
|
assert(page_type == SLOTTED_PAGE ||
|
||||||
page_type == BOUNDARY_TAG_PAGE ||
|
page_type == BOUNDARY_TAG_PAGE ||
|
||||||
page_type == SLOTTED_LSN_FREE_PAGE);
|
page_type == SLOTTED_LSN_FREE_PAGE ||
|
||||||
|
page_type == SLOTTED_LATCH_FREE_PAGE);
|
||||||
assert(numslots >= 0);
|
assert(numslots >= 0);
|
||||||
assert(numslots * SLOTTED_PAGE_OVERHEAD_PER_RECORD < PAGE_SIZE);
|
assert(numslots * SLOTTED_PAGE_OVERHEAD_PER_RECORD < PAGE_SIZE);
|
||||||
assert(freespace >= 0);
|
assert(freespace >= 0);
|
||||||
|
|
|
@ -235,6 +235,7 @@ static const short SLOT_TYPE_LENGTHS[] = { -1, -1, sizeof(blob_record_t), -1};
|
||||||
#define SLOTTED_LSN_FREE_PAGE 10
|
#define SLOTTED_LSN_FREE_PAGE 10
|
||||||
#define SEGMENT_PAGE 11
|
#define SEGMENT_PAGE 11
|
||||||
#define MULTI_PAGE 12 // Not really a page type, but used to denote operations that touch many pages.
|
#define MULTI_PAGE 12 // Not really a page type, but used to denote operations that touch many pages.
|
||||||
|
#define SLOTTED_LATCH_FREE_PAGE 13
|
||||||
#define USER_DEFINED_PAGE(n) (100+n) // 0 <= n < 155
|
#define USER_DEFINED_PAGE(n) (100+n) // 0 <= n < 155
|
||||||
#define MAX_PAGE_TYPE 255
|
#define MAX_PAGE_TYPE 255
|
||||||
|
|
||||||
|
|
|
@ -917,6 +917,7 @@ page_impl* stasis_page_impl_get(int id);
|
||||||
returned by loadPage()
|
returned by loadPage()
|
||||||
*/
|
*/
|
||||||
void stasis_page_slotted_initialize_page(Page * p);
|
void stasis_page_slotted_initialize_page(Page * p);
|
||||||
|
void stasis_page_slotted_latch_free_initialize_page(Page * page);
|
||||||
void stasis_slotted_lsn_free_initialize_page(Page * p);
|
void stasis_slotted_lsn_free_initialize_page(Page * p);
|
||||||
void stasis_fixed_initialize_page(Page * page, size_t size, int count);
|
void stasis_fixed_initialize_page(Page * page, size_t size, int count);
|
||||||
void stasis_indirect_initialize_page(Page * p, int height);
|
void stasis_indirect_initialize_page(Page * p, int height);
|
||||||
|
|
34
stasis/page/latchFree/lfSlotted.h
Normal file
34
stasis/page/latchFree/lfSlotted.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* @file A special-purpose slotted page implementation for latch-free data structures
|
||||||
|
*
|
||||||
|
* This page format is similar to that provided by slotted.h (and
|
||||||
|
* uses an identical layout). The difference is that this format
|
||||||
|
* allows readers and writers to access the same page concurrently.
|
||||||
|
*
|
||||||
|
* It does so by making use of GCC atomic operations, and by providing
|
||||||
|
* a restricted API.
|
||||||
|
*
|
||||||
|
* Only one thread may write to a given page at a time (this restriction
|
||||||
|
* may be limited in the future), records may only be written once, and
|
||||||
|
* the space taken up by freed records is not reused. Instead, the writer
|
||||||
|
* thread must (somhehow) ensure that no readers are accessing the page,
|
||||||
|
* and then must either reinitialize the page (losing its contents), or
|
||||||
|
* simply free the page, allowing Stasis' page allocation routines to
|
||||||
|
* reuse the underlying storage.
|
||||||
|
*
|
||||||
|
* Readers are latch-free; they do not perform any explicit synchronization
|
||||||
|
* with the writer, except when they synchronize so that space can be reused.
|
||||||
|
*
|
||||||
|
* Created on: Aug 19, 2010
|
||||||
|
* Author: sears
|
||||||
|
*/
|
||||||
|
#ifndef LFSLOTTED_H_
|
||||||
|
#define LFSLOTTED_H_
|
||||||
|
|
||||||
|
#include <stasis/page/slotted.h>
|
||||||
|
|
||||||
|
void stasis_page_slotted_latch_free_init();
|
||||||
|
void stasis_page_slotted_latch_free_deinit();
|
||||||
|
page_impl stasis_page_slotted_latch_free_impl();
|
||||||
|
|
||||||
|
#endif /* LFSLOTTED_H_ */
|
|
@ -59,7 +59,8 @@ Slotted page layout:
|
||||||
has been handled, except in slottedPostRalloc...
|
has been handled, except in slottedPostRalloc...
|
||||||
|
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
#ifndef STASIS_PAGE_SLOTTED_H
|
||||||
|
#define STASIS_PAGE_SLOTTED_H
|
||||||
static inline int16_t* stasis_page_slotted_freespace_ptr(Page * p) { return stasis_page_int16_ptr_from_end((p), 1); }
|
static inline int16_t* stasis_page_slotted_freespace_ptr(Page * p) { return stasis_page_int16_ptr_from_end((p), 1); }
|
||||||
static inline int16_t* stasis_page_slotted_numslots_ptr(Page * p) { return stasis_page_int16_ptr_from_end(p, 2); }
|
static inline int16_t* stasis_page_slotted_numslots_ptr(Page * p) { return stasis_page_int16_ptr_from_end(p, 2); }
|
||||||
static inline int16_t* stasis_page_slotted_freelist_ptr(Page * p) { return stasis_page_int16_ptr_from_end(p, 3); }
|
static inline int16_t* stasis_page_slotted_freelist_ptr(Page * p) { return stasis_page_int16_ptr_from_end(p, 3); }
|
||||||
|
@ -78,3 +79,4 @@ void stasis_page_slotted_init();
|
||||||
void stasis_page_slotted_deinit();
|
void stasis_page_slotted_deinit();
|
||||||
page_impl stasis_page_slotted_impl();
|
page_impl stasis_page_slotted_impl();
|
||||||
page_impl stasis_page_boundary_tag_impl();
|
page_impl stasis_page_boundary_tag_impl();
|
||||||
|
#endif //STASIS_PAGE_SLOTTED_H
|
||||||
|
|
|
@ -48,6 +48,7 @@ terms specified in this license.
|
||||||
|
|
||||||
#include <stasis/page.h>
|
#include <stasis/page.h>
|
||||||
#include <stasis/page/slotted.h>
|
#include <stasis/page/slotted.h>
|
||||||
|
#include <stasis/page/latchFree/lfSlotted.h>
|
||||||
#include <stasis/blobManager.h>
|
#include <stasis/blobManager.h>
|
||||||
#include <stasis/bufferManager.h>
|
#include <stasis/bufferManager.h>
|
||||||
#include <stasis/transactional.h>
|
#include <stasis/transactional.h>
|
||||||
|
@ -152,6 +153,78 @@ static void* fixed_worker_thread(void * arg_ptr) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Page ** pages;
|
||||||
|
int num_pages;
|
||||||
|
int my_page;
|
||||||
|
} latchFree_worker_thread_args;
|
||||||
|
|
||||||
|
static void* latchFree_worker_thread(void * arg_ptr) {
|
||||||
|
latchFree_worker_thread_args * arg = arg_ptr;
|
||||||
|
|
||||||
|
int alloced_count = 0;
|
||||||
|
while(1) {
|
||||||
|
int off = myrandom(arg->num_pages);
|
||||||
|
Page * p = arg->pages[off];
|
||||||
|
if(off == arg->my_page) {
|
||||||
|
recordid rid = stasis_record_alloc_begin(-1, p, sizeof(char));
|
||||||
|
if(rid.size == INVALID_SLOT) {
|
||||||
|
assert(alloced_count > 200);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
stasis_record_alloc_done(-1, p, rid);
|
||||||
|
alloced_count++;
|
||||||
|
assert(alloced_count < PAGE_SIZE/2);
|
||||||
|
unsigned char c = (unsigned char)rid.slot;
|
||||||
|
stasis_record_write(-1, p, rid, &c);
|
||||||
|
}
|
||||||
|
} else if(*stasis_page_slotted_numslots_cptr(p)) { // if the page is empty, try another.
|
||||||
|
// read a random record
|
||||||
|
int slot = myrandom(stasis_record_last(-1, p).slot+1);
|
||||||
|
recordid rid;
|
||||||
|
rid.page = p->id;
|
||||||
|
rid.slot = slot;
|
||||||
|
rid.size = sizeof(char);
|
||||||
|
assert(stasis_record_type_read(-1, p, rid) == NORMAL_SLOT);
|
||||||
|
assert(stasis_record_length_read(-1, p, rid) == sizeof(char));
|
||||||
|
unsigned char c = 0;
|
||||||
|
stasis_record_read(-1, p, rid, &c);
|
||||||
|
assert(c == (unsigned char) rid.slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
START_TEST(latchFreeThreadTest) {
|
||||||
|
Tinit();
|
||||||
|
int NUM_THREADS = 200;
|
||||||
|
Page ** pages = malloc(sizeof(Page*)*NUM_THREADS);
|
||||||
|
int xid = Tbegin();
|
||||||
|
|
||||||
|
pageid_t region = TregionAlloc(xid, NUM_THREADS, -1);
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_THREADS; i++) {
|
||||||
|
pages[i] = loadPage(xid, i+region);
|
||||||
|
stasis_page_slotted_latch_free_initialize_page(pages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t * threads = malloc(sizeof(pthread_t) * NUM_THREADS);
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_THREADS; i++) {
|
||||||
|
latchFree_worker_thread_args * arg = malloc(sizeof(*arg));
|
||||||
|
arg->pages = pages;
|
||||||
|
arg->my_page = i;
|
||||||
|
arg->num_pages = NUM_THREADS;
|
||||||
|
pthread_create(&threads[i], 0, &latchFree_worker_thread, arg);
|
||||||
|
}
|
||||||
|
for(int i = 0; i < NUM_THREADS; i++) {
|
||||||
|
pthread_join(threads[i],0);
|
||||||
|
}
|
||||||
|
for(int i = 0; i < NUM_THREADS; i++) {
|
||||||
|
releasePage(pages[i]);
|
||||||
|
}
|
||||||
|
Tcommit(xid);
|
||||||
|
Tdeinit();
|
||||||
|
|
||||||
|
} END_TEST
|
||||||
static void* worker_thread(void * arg_ptr) {
|
static void* worker_thread(void * arg_ptr) {
|
||||||
Page * p = (Page*)arg_ptr;
|
Page * p = (Page*)arg_ptr;
|
||||||
int i;
|
int i;
|
||||||
|
@ -313,9 +386,12 @@ static void assertRecordCountSizeType(int xid, Page *p, int count, int size, int
|
||||||
static void checkPageIterators(int xid, Page *p,int record_count) {
|
static void checkPageIterators(int xid, Page *p,int record_count) {
|
||||||
recordid first = stasis_record_alloc_begin(xid, p, sizeof(int64_t));
|
recordid first = stasis_record_alloc_begin(xid, p, sizeof(int64_t));
|
||||||
stasis_record_alloc_done(xid,p,first);
|
stasis_record_alloc_done(xid,p,first);
|
||||||
|
int64_t i = 0;
|
||||||
for(int i = 1; i < record_count; i++) {
|
stasis_record_write(xid,p,first,(byte*)&i);
|
||||||
stasis_record_alloc_done(xid,p,stasis_record_alloc_begin(xid,p,sizeof(int64_t)));
|
for(i = 1; i < record_count; i++) {
|
||||||
|
recordid rid = stasis_record_alloc_begin(xid,p,sizeof(int64_t));
|
||||||
|
stasis_record_alloc_done(xid,p,rid);
|
||||||
|
stasis_record_write(xid,p,rid,(byte*)&i);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertRecordCountSizeType(xid, p, record_count, sizeof(int64_t), NORMAL_SLOT);
|
assertRecordCountSizeType(xid, p, record_count, sizeof(int64_t), NORMAL_SLOT);
|
||||||
|
@ -356,6 +432,11 @@ START_TEST(pageRecordSizeTypeIteratorTest) {
|
||||||
|
|
||||||
checkPageIterators(xid,p,10);
|
checkPageIterators(xid,p,10);
|
||||||
|
|
||||||
|
memset(p->memAddr, 0, PAGE_SIZE);
|
||||||
|
stasis_page_slotted_latch_free_initialize_page(p);
|
||||||
|
|
||||||
|
checkPageIterators(xid,p,10);
|
||||||
|
|
||||||
releasePage(p);
|
releasePage(p);
|
||||||
|
|
||||||
Tcommit(xid);
|
Tcommit(xid);
|
||||||
|
@ -647,6 +728,7 @@ Suite * check_suite(void) {
|
||||||
tcase_add_test(tc, pageNoThreadTest);
|
tcase_add_test(tc, pageNoThreadTest);
|
||||||
tcase_add_test(tc, pageThreadTest);
|
tcase_add_test(tc, pageThreadTest);
|
||||||
tcase_add_test(tc, fixedPageThreadTest);
|
tcase_add_test(tc, fixedPageThreadTest);
|
||||||
|
tcase_add_test(tc, latchFreeThreadTest);
|
||||||
|
|
||||||
/* --------------------------------------------- */
|
/* --------------------------------------------- */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue