Cleaned out old cruft, such as commented out code, dead data structures, and dead files. sloccount went from $75,000 to $50,000 on src/lladd. ;)
This commit is contained in:
parent
fab0e6cbbd
commit
c4fac084b8
22 changed files with 141 additions and 2202 deletions
|
@ -47,6 +47,20 @@ terms specified in this license.
|
||||||
* It would be nice if the logger API could be simplified by having
|
* It would be nice if the logger API could be simplified by having
|
||||||
* more of its functionality handled this way.
|
* more of its functionality handled this way.
|
||||||
*
|
*
|
||||||
|
Implementation notes:
|
||||||
|
|
||||||
|
- Just a Tupdate, with a log flush as its operationsTable[]
|
||||||
|
function.
|
||||||
|
|
||||||
|
- After recovery, all of the xacts pages will have been 'stolen',
|
||||||
|
(if recovery flushes dirty pages)
|
||||||
|
|
||||||
|
- Recovery function needs to distinguish between actions before and
|
||||||
|
after the last Tprepare log entry. This is handle by a guard on
|
||||||
|
the logHandle's iterator, but could be generalized in the future
|
||||||
|
(to support savepoints, for example) Right now, recovery uses a
|
||||||
|
guarded iterator, transUndo() does not.
|
||||||
|
|
||||||
*
|
*
|
||||||
* @ingroup OPERATIONS
|
* @ingroup OPERATIONS
|
||||||
*
|
*
|
||||||
|
@ -61,11 +75,23 @@ terms specified in this license.
|
||||||
#include <lladd/operations.h>
|
#include <lladd/operations.h>
|
||||||
|
|
||||||
extern recordid prepare_bogus_rec;
|
extern recordid prepare_bogus_rec;
|
||||||
|
/**
|
||||||
|
Prepare transaction for commit. Currently, a transaction may be
|
||||||
|
prepared multiple times. Once Tprepare() returns, the caller is
|
||||||
|
guaranteed that the current transaction will resume exactly where
|
||||||
|
it was when Tprepare() was called.
|
||||||
|
|
||||||
|
@param xid Transaction id.
|
||||||
|
@param rec @todo undocumented.
|
||||||
|
@param dat @todo Ignored for now?
|
||||||
|
*/
|
||||||
#define Tprepare(xid, rec, dat) Tupdate(xid, rec, 0, OPERATION_PREPARE)
|
#define Tprepare(xid, rec, dat) Tupdate(xid, rec, 0, OPERATION_PREPARE)
|
||||||
|
|
||||||
Operation getPrepare();
|
Operation getPrepare();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Recovery's undo phase uses this logHandle iterator guard to implement Tprepare().
|
||||||
|
*/
|
||||||
int prepareGuard(LogEntry * e, void * state);
|
int prepareGuard(LogEntry * e, void * state);
|
||||||
void * getPrepareGuardState();
|
void * getPrepareGuardState();
|
||||||
#endif
|
#endif
|
||||||
|
|
12
lladd/page.h
12
lladd/page.h
|
@ -83,17 +83,6 @@ typedef struct Page_s {
|
||||||
int queue;
|
int queue;
|
||||||
} Page;
|
} Page;
|
||||||
|
|
||||||
/**
|
|
||||||
* tracks changes to blobs
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
int xid;
|
|
||||||
recordid *records;
|
|
||||||
size_t len;
|
|
||||||
} touchedBlob_t;
|
|
||||||
|
|
||||||
#define DEFAULT_TOUCHED 2
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initializes all the important variables needed in all the
|
* initializes all the important variables needed in all the
|
||||||
* functions dealing with pages.
|
* functions dealing with pages.
|
||||||
|
@ -143,7 +132,6 @@ Page* pageAlloc(int id);
|
||||||
recordid pageSlotRalloc(Page page, recordid rid);
|
recordid pageSlotRalloc(Page page, recordid rid);
|
||||||
|
|
||||||
int pageTest();
|
int pageTest();
|
||||||
recordid pageBalloc(Page page, int size, int offset);
|
|
||||||
|
|
||||||
int getSlotType(Page p, int slot, int type);
|
int getSlotType(Page p, int slot, int type);
|
||||||
void setSlotType(Page p, int slot, int type);
|
void setSlotType(Page p, int slot, int type);
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
/* stdio */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
@ -36,13 +34,12 @@ static void readRawRecord(int xid, recordid rid, void * buf, int size) {
|
||||||
static void writeRawRecord(int xid, lsn_t lsn, recordid rid, const void * buf, int size) {
|
static void writeRawRecord(int xid, lsn_t lsn, recordid rid, const void * buf, int size) {
|
||||||
recordid blob_rec_rid = rid;
|
recordid blob_rec_rid = rid;
|
||||||
blob_rec_rid.size = size;
|
blob_rec_rid.size = size;
|
||||||
/* writeRecord(xid, lsn, blob_rec_rid, buf); */
|
|
||||||
Tset(xid, blob_rec_rid, buf);
|
Tset(xid, blob_rec_rid, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* moved verbatim from bufferManger.c */
|
/* moved verbatim from bufferManger.c, then hacked up to use FILE * instead of ints. */
|
||||||
void openBlobStore() {
|
void openBlobStore() {
|
||||||
int blobfd0, blobfd1;
|
int blobfd0, blobfd1;
|
||||||
if( ! (blobf0 = fopen(BLOB0_FILE, "w+"))) { /* file may not exist */
|
if( ! (blobf0 = fopen(BLOB0_FILE, "w+"))) { /* file may not exist */
|
||||||
|
@ -114,7 +111,6 @@ recordid allocBlob(int xid, lsn_t lsn, size_t blobSize) {
|
||||||
assert(blobSize > 0); /* Don't support zero length blobs right now... */
|
assert(blobSize > 0); /* Don't support zero length blobs right now... */
|
||||||
|
|
||||||
/* First in buffer manager. */
|
/* First in buffer manager. */
|
||||||
/* recordid rid = ralloc(xid, lsn, sizeof(blob_record_t)); */
|
|
||||||
|
|
||||||
recordid rid = Talloc(xid, sizeof(blob_record_t));
|
recordid rid = Talloc(xid, sizeof(blob_record_t));
|
||||||
|
|
||||||
|
@ -143,9 +139,10 @@ recordid allocBlob(int xid, lsn_t lsn, size_t blobSize) {
|
||||||
|
|
||||||
setSlotType(p, rid.slot, BLOB_SLOT);
|
setSlotType(p, rid.slot, BLOB_SLOT);
|
||||||
rid.size = BLOB_SLOT;
|
rid.size = BLOB_SLOT;
|
||||||
/* writeRecord needs to know to 'do the right thing' here, since
|
|
||||||
we've changed the size it has recorded for this record. */
|
/* Tset() needs to know to 'do the right thing' here, since we've
|
||||||
/* @todo What should writeRawRecord do with the lsn? */
|
changed the size it has recorded for this record, and
|
||||||
|
writeRawRecord makes sure that that is the case. */
|
||||||
writeRawRecord (xid, lsn, rid, &blob_rec, sizeof(blob_record_t));
|
writeRawRecord (xid, lsn, rid, &blob_rec, sizeof(blob_record_t));
|
||||||
|
|
||||||
rid.size = blob_rec.size;
|
rid.size = blob_rec.size;
|
||||||
|
@ -220,12 +217,11 @@ static void tripleHashRemove(int xid, recordid rid) {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
void readBlob(int xid, recordid rid, void * buf) {
|
void readBlob(int xid, recordid rid, void * buf) {
|
||||||
/* First, determine if the blob is dirty. */
|
|
||||||
|
|
||||||
/* lsn_t * dirty = tripleHashLookup(xid, rid); */
|
/* We don't care if the blob is dirty, since the record from the
|
||||||
|
buffer manager will reflect that if it is.. */
|
||||||
|
|
||||||
blob_record_t rec;
|
blob_record_t rec;
|
||||||
/* int readcount; */
|
|
||||||
FILE * fd;
|
FILE * fd;
|
||||||
long offset;
|
long offset;
|
||||||
|
|
||||||
|
@ -233,14 +229,6 @@ void readBlob(int xid, recordid rid, void * buf) {
|
||||||
|
|
||||||
readRawRecord(xid, rid, &rec, sizeof(blob_record_t));
|
readRawRecord(xid, rid, &rec, sizeof(blob_record_t));
|
||||||
|
|
||||||
/* if(dirty) {
|
|
||||||
DEBUG("Reading dirty blob.\n");
|
|
||||||
fd = rec.fd ? blobf0 : blobf1; / * Read the updated version * /
|
|
||||||
} else {
|
|
||||||
DEBUG("Reading clean blob.\n");
|
|
||||||
fd = rec.fd ? blobf1 : blobf0; / * Read the clean version * /
|
|
||||||
} */
|
|
||||||
|
|
||||||
fd = rec.fd ? blobf1 : blobf0;
|
fd = rec.fd ? blobf1 : blobf0;
|
||||||
|
|
||||||
offset = myFseek(fd, (long int) rec.offset, SEEK_SET);
|
offset = myFseek(fd, (long int) rec.offset, SEEK_SET);
|
||||||
|
@ -261,9 +249,10 @@ void readBlob(int xid, recordid rid, void * buf) {
|
||||||
current version of the dirty blob, and the lsn field should be
|
current version of the dirty blob, and the lsn field should be
|
||||||
checked to be sure that it increases monotonically. */
|
checked to be sure that it increases monotonically. */
|
||||||
void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
||||||
/* First, determine if the blob is dirty. */
|
|
||||||
|
|
||||||
|
/* First, determine if the blob is dirty. */
|
||||||
lsn_t * dirty = tripleHashLookup(xid, rid);
|
lsn_t * dirty = tripleHashLookup(xid, rid);
|
||||||
|
|
||||||
blob_record_t rec;
|
blob_record_t rec;
|
||||||
long offset;
|
long offset;
|
||||||
FILE * fd;
|
FILE * fd;
|
||||||
|
@ -274,7 +263,7 @@ void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
||||||
|
|
||||||
if(dirty) {
|
if(dirty) {
|
||||||
assert(lsn > *dirty);
|
assert(lsn > *dirty);
|
||||||
*dirty = lsn; /* Updates value in dirty blobs (works because of pointer aliasing.) */
|
*dirty = lsn; /* Updates value in triple hash (works because of pointer aliasing.) */
|
||||||
DEBUG("Blob already dirty.\n");
|
DEBUG("Blob already dirty.\n");
|
||||||
|
|
||||||
|
|
||||||
|
@ -288,12 +277,6 @@ void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
||||||
/* Tset() raw record */
|
/* Tset() raw record */
|
||||||
writeRawRecord(xid, lsn, rid, &rec, sizeof(blob_record_t));
|
writeRawRecord(xid, lsn, rid, &rec, sizeof(blob_record_t));
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
readRawRecord(xid, rid, &rec, sizeof(blob_record_t));
|
|
||||||
|
|
||||||
fd = rec.fd ? blobf0 : blobf1; / * Read the slot for the dirty (updated) version. * /
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
fd = rec.fd ? blobf1 : blobf0; /* rec's fd is up-to-date, so use it directly */
|
fd = rec.fd ? blobf1 : blobf0; /* rec's fd is up-to-date, so use it directly */
|
||||||
|
|
||||||
|
@ -307,83 +290,41 @@ void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
||||||
/* No need to update the raw blob record. */
|
/* No need to update the raw blob record. */
|
||||||
|
|
||||||
}
|
}
|
||||||
/** @todo check return values */
|
|
||||||
/*
|
|
||||||
void commitBlobs(int xid, lsn_t lsn) {
|
|
||||||
/ * Because this is a commit, we must update each page atomically.
|
|
||||||
Therefore, we need to re-group the dirtied blobs by page id, and
|
|
||||||
then issue one write per page. Since we write flip the bits of each
|
|
||||||
dirty blob record on the page, we can't get away with incrementally
|
|
||||||
updating things. * /
|
|
||||||
|
|
||||||
pblHashTable_t * rid_buckets = pblHtLookup(dirtyBlobs, &xid, sizeof(int));
|
|
||||||
|
|
||||||
pblHashTable_t * this_bucket;
|
|
||||||
|
|
||||||
if(!rid_buckets) { return; } / * No blobs for this xid. * /
|
|
||||||
|
|
||||||
for(this_bucket = pblHtFirst(rid_buckets); this_bucket; this_bucket = pblHtNext(rid_buckets)) {
|
|
||||||
blob_record_t buf;
|
|
||||||
recordid * rid_ptr;
|
|
||||||
lsn_t * rid_lsn;
|
|
||||||
int first = 1;
|
|
||||||
int page_number;
|
|
||||||
/ * All right, this_bucket contains all of the rids for this page. * /
|
|
||||||
|
|
||||||
for(rid_lsn = pblHtFirst(this_bucket); rid_lsn; rid_lsn = pblHtNext(this_bucket)) {
|
|
||||||
/ ** @todo INTERFACE VIOLATION Can only use bufferManager's
|
|
||||||
read/write record since we're single threaded, and this calling
|
|
||||||
sequence cannot possibly call kick page. Really, we sould use
|
|
||||||
pageReadRecord / pageWriteRecord, and bufferManager should let
|
|
||||||
us write out the whole page atomically... * /
|
|
||||||
|
|
||||||
rid_ptr = pblHtCurrentKey(this_bucket);
|
|
||||||
|
|
||||||
if(first) {
|
|
||||||
page_number = rid_ptr->page;
|
|
||||||
first = 0;
|
|
||||||
} else {
|
|
||||||
assert(page_number == rid_ptr->page);
|
|
||||||
}
|
|
||||||
|
|
||||||
/ ** @todo For now, we assume that overlapping transactions (from
|
|
||||||
the Tbegin() to Tcommit() call) do not access the same
|
|
||||||
blob. * /
|
|
||||||
|
|
||||||
readRawRecord(xid, *rid_ptr, &buf, sizeof(blob_record_t));
|
|
||||||
/ * This rid is dirty, so swap the fd pointer. * /
|
|
||||||
buf.fd = (buf.fd ? 0 : 1);
|
|
||||||
writeRawRecord(xid, lsn, *rid_ptr, &buf, sizeof(blob_record_t));
|
|
||||||
pblHtRemove(this_bucket, rid_ptr, sizeof(recordid));
|
|
||||||
/ * free(rid_ptr); * /
|
|
||||||
free(rid_lsn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!first) {
|
|
||||||
pblHtRemove(rid_buckets, &page_number, sizeof(int));
|
|
||||||
} else {
|
|
||||||
abort(); / * Bucket existed, but was empty?!? * /
|
|
||||||
}
|
|
||||||
|
|
||||||
pblHtDelete(this_bucket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void commitBlobs(int xid) {
|
void commitBlobs(int xid) {
|
||||||
abortBlobs(xid);
|
abortBlobs(xid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Just clean up the dirty list for this xid. @todo Check return values.
|
Just clean up the dirty list for this xid. @todo Check return values.
|
||||||
|
|
||||||
(Functionally equivalent to the old rmTouch() function. Just
|
(Functionally equivalent to the old rmTouch() function. Just
|
||||||
deletes this xid's dirty list.)
|
deletes this xid's dirty list.)
|
||||||
|
|
||||||
@todo doesn't take lsn_t, since it doesnt write any blobs. Change the api?
|
@todo doesn't take lsn_t, since it doesnt write any blobs. Change
|
||||||
|
the api?
|
||||||
|
|
||||||
|
@todo The tripleHash data structure is overkill here. We only
|
||||||
|
need two layers of hash tables, but it works, and it would be a
|
||||||
|
pain to change it, unless we need to touch this file for some
|
||||||
|
other reason.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void abortBlobs(int xid) {
|
void abortBlobs(int xid) {
|
||||||
pblHashTable_t * rid_buckets = pblHtLookup(dirtyBlobs, &xid, sizeof(int));
|
/*
|
||||||
|
At first glance, it may seem easier to keep track of which blobs
|
||||||
|
are dirty only in blobManager, and then propogate those updates to
|
||||||
|
bufferManager later. It turns out that it's much easier to
|
||||||
|
propogate the changes to bufferManger, since otherwise, recovery
|
||||||
|
and undo have to reason about lazy propogation of values to the
|
||||||
|
bufferManager, and also have to preserve *write* ordering, even
|
||||||
|
though the writes may be across many transactions, and could be
|
||||||
|
propogated in the wrong order. If we generate a Tset() (for the
|
||||||
|
blob record in bufferManager) for each write, things become much
|
||||||
|
easier.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pblHashTable_t * rid_buckets = pblHtLookup(dirtyBlobs, &xid, sizeof(int));
|
||||||
pblHashTable_t * this_bucket;
|
pblHashTable_t * this_bucket;
|
||||||
|
|
||||||
if(!rid_buckets) { return; } /* No dirty blobs for this xid.. */
|
if(!rid_buckets) { return; } /* No dirty blobs for this xid.. */
|
||||||
|
@ -391,6 +332,7 @@ void abortBlobs(int xid) {
|
||||||
for(this_bucket = pblHtFirst(rid_buckets); this_bucket; this_bucket = pblHtNext(rid_buckets)) {
|
for(this_bucket = pblHtFirst(rid_buckets); this_bucket; this_bucket = pblHtNext(rid_buckets)) {
|
||||||
lsn_t * rid_lsn;
|
lsn_t * rid_lsn;
|
||||||
int page_number;
|
int page_number;
|
||||||
|
|
||||||
/* All right, this_bucket contains all of the rids for this page. */
|
/* All right, this_bucket contains all of the rids for this page. */
|
||||||
|
|
||||||
for(rid_lsn = pblHtFirst(this_bucket); rid_lsn; rid_lsn = pblHtNext(this_bucket)) {
|
for(rid_lsn = pblHtFirst(this_bucket); rid_lsn; rid_lsn = pblHtNext(this_bucket)) {
|
||||||
|
|
|
@ -38,21 +38,19 @@ BEGIN_C_DECLS
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If blob is resident, return a pointer to it. Otherwise, check if
|
Read the blob from the recordid rid into buf.
|
||||||
it's dirty (it could have been stolen), an retrieve it from the
|
|
||||||
appropriate blob file.
|
|
||||||
*/
|
*/
|
||||||
void readBlob(int xid, recordid rid, void * buf);
|
void readBlob(int xid, recordid rid, void * buf);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If you write to a blob, call this function to mark it dirty.
|
Write the contents of buf to the blob in recordid rid.
|
||||||
*/
|
*/
|
||||||
void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf);
|
void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Atomically (with respect to recovery) make the dirty version of the
|
Atomicly (with respect to recovery) make the dirty version of the
|
||||||
blob the primary copy and mark it not-dirty.
|
blob the primary copy and mark it not-dirty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -70,6 +68,12 @@ typedef struct {
|
||||||
unsigned fd : 1;
|
unsigned fd : 1;
|
||||||
} blob_record_t;
|
} blob_record_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Allocate a blob of size blobSize.
|
||||||
|
|
||||||
|
@todo This function does not atomically allocate space in the blob
|
||||||
|
file.
|
||||||
|
*/
|
||||||
recordid allocBlob(int xid, lsn_t lsn, size_t blobSize);
|
recordid allocBlob(int xid, lsn_t lsn, size_t blobSize);
|
||||||
void openBlobStore();
|
void openBlobStore();
|
||||||
void closeBlobStore();
|
void closeBlobStore();
|
||||||
|
|
|
@ -68,8 +68,6 @@ static unsigned int bufferSize = 1; /* < MAX_BUFFER_SIZE */
|
||||||
static Page *repHead, *repMiddle, *repTail; /* replacement policy */
|
static Page *repHead, *repMiddle, *repTail; /* replacement policy */
|
||||||
|
|
||||||
static int stable = -1;
|
static int stable = -1;
|
||||||
/*int blobfd0 = -1;
|
|
||||||
int blobfd1 = -1;*/
|
|
||||||
|
|
||||||
static void pageMap(Page *ret) {
|
static void pageMap(Page *ret) {
|
||||||
|
|
||||||
|
@ -95,12 +93,8 @@ int bufInit() {
|
||||||
|
|
||||||
bufferSize = 1;
|
bufferSize = 1;
|
||||||
stable = -1;
|
stable = -1;
|
||||||
/* blobfd0 = -1;
|
|
||||||
blobfd1 = -1; */
|
|
||||||
|
|
||||||
|
/* Create STORE_FILE, if necessary, then open it read/write
|
||||||
/* Create STORE_FILE, BLOB0_FILE, BLOB1_FILE if necessary,
|
|
||||||
then open it read/write
|
|
||||||
|
|
||||||
If we're creating it, then put one all-zero record at the beginning of it.
|
If we're creating it, then put one all-zero record at the beginning of it.
|
||||||
(Need to have at least one record in the PAGE file?)
|
(Need to have at least one record in the PAGE file?)
|
||||||
|
@ -141,27 +135,6 @@ int bufInit() {
|
||||||
|
|
||||||
openBlobStore();
|
openBlobStore();
|
||||||
|
|
||||||
/* if( (blobfd0 = open(BLOB0_FILE, O_RDWR, 0)) == -1 ) { / * file may not exist * /
|
|
||||||
if( (blobfd0 = creat(BLOB0_FILE, 0666)) == -1 ) { / * cannot even create it * /
|
|
||||||
printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__);
|
|
||||||
exit(errno);
|
|
||||||
}
|
|
||||||
if( close(blobfd0) || ((blobfd0 = open(BLOB0_FILE, O_RDWR, 0)) == -1) ) { / * need to reopen with read perms * /
|
|
||||||
printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__);
|
|
||||||
exit(errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( (blobfd1 = open(BLOB1_FILE, O_RDWR, 0)) == -1 ) { / * file may not exist * /
|
|
||||||
if( (blobfd1 = creat(BLOB1_FILE, 0666)) == -1 ) { / * cannot even create it * /
|
|
||||||
printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__);
|
|
||||||
exit(errno);
|
|
||||||
}
|
|
||||||
if( close(blobfd1) || ((blobfd1 = open(BLOB1_FILE, O_RDWR, 0)) == -1) ) { / * need to reopen with read perms * /
|
|
||||||
printf("ERROR: %i on %s line %d", errno, __FILE__, __LINE__);
|
|
||||||
exit(errno);
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,8 +192,14 @@ static void qRemove(Page *ret) {
|
||||||
assert(ret != repHead);
|
assert(ret != repHead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
LRU-2S from Markatos "On Caching Searching Engine Results"
|
||||||
|
|
||||||
|
@todo Should this be its own file?
|
||||||
|
|
||||||
|
*/
|
||||||
static Page *kickPage(int pageid) {
|
static Page *kickPage(int pageid) {
|
||||||
/* LRU-2S from Markatos "On Caching Searching Engine Results" */
|
|
||||||
Page *ret = repTail;
|
Page *ret = repTail;
|
||||||
|
|
||||||
assert( bufferSize == MAX_BUFFER_SIZE );
|
assert( bufferSize == MAX_BUFFER_SIZE );
|
||||||
|
@ -328,38 +307,22 @@ Page loadPage (int pageid) {
|
||||||
return *loadPagePtr(pageid);
|
return *loadPagePtr(pageid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int lastGoodPageKey = 0; */
|
|
||||||
|
|
||||||
Page * lastRallocPage = 0;
|
Page * lastRallocPage = 0;
|
||||||
|
|
||||||
recordid ralloc(int xid, lsn_t lsn, size_t size) {
|
recordid ralloc(int xid, lsn_t lsn, size_t size) {
|
||||||
static unsigned int lastFreepage = 0;
|
static unsigned int lastFreepage = 0;
|
||||||
recordid ret;
|
recordid ret;
|
||||||
Page p;
|
Page p;
|
||||||
/* int blobSize = 0; */
|
|
||||||
|
|
||||||
if (size >= BLOB_THRESHOLD_SIZE) { /* TODO combine this with if below */
|
if (size >= BLOB_THRESHOLD_SIZE) { /* TODO combine this with if below */
|
||||||
|
|
||||||
ret = allocBlob(xid, lsn, size);
|
ret = allocBlob(xid, lsn, size);
|
||||||
/* blobSize = size;
|
|
||||||
size = BLOB_REC_SIZE; */
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
while(freespace(p = loadPage(lastFreepage)) < size ) { lastFreepage++; }
|
while(freespace(p = loadPage(lastFreepage)) < size ) { lastFreepage++; }
|
||||||
|
|
||||||
/* if (blobSize >= BLOB_THRESHOLD_SIZE) {
|
|
||||||
int fileSize = (int) lseek(blobfd1, 0 , SEEK_END);
|
|
||||||
/ * fstat(blobfd1, &sb);
|
|
||||||
fileSize = (int) sb.st_size; * /
|
|
||||||
lseek(blobfd0, fileSize+blobSize-1, SEEK_SET);
|
|
||||||
write(blobfd0, "", 1);
|
|
||||||
lseek(blobfd1, fileSize+blobSize-1, SEEK_SET);
|
|
||||||
write(blobfd1, "", 1);
|
|
||||||
|
|
||||||
return pageBalloc(p, blobSize, fileSize);
|
|
||||||
} else { */
|
|
||||||
ret = pageRalloc(p, size);
|
ret = pageRalloc(p, size);
|
||||||
|
|
||||||
/* } */
|
|
||||||
}
|
}
|
||||||
DEBUG("alloced rid = {%d, %d, %d}\n", ret.page, ret.slot, ret.size);
|
DEBUG("alloced rid = {%d, %d, %d}\n", ret.page, ret.slot, ret.size);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -441,7 +404,6 @@ void bufDeinit() {
|
||||||
printf("ERROR: flushPage on %s line %d", __FILE__, __LINE__);
|
printf("ERROR: flushPage on %s line %d", __FILE__, __LINE__);
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
/* free(p); */
|
|
||||||
}
|
}
|
||||||
pblHtDelete(activePages);
|
pblHtDelete(activePages);
|
||||||
|
|
||||||
|
@ -450,8 +412,6 @@ void bufDeinit() {
|
||||||
exit(errno);
|
exit(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close(blobfd0);
|
|
||||||
close(blobfd1); */
|
|
||||||
closeBlobStore();
|
closeBlobStore();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -462,12 +422,8 @@ void bufDeinit() {
|
||||||
*/
|
*/
|
||||||
void simulateBufferManagerCrash() {
|
void simulateBufferManagerCrash() {
|
||||||
closeBlobStore();
|
closeBlobStore();
|
||||||
/*close(blobfd0);
|
|
||||||
close(blobfd1);*/
|
|
||||||
close(stable);
|
close(stable);
|
||||||
/* blobfd0 = -1;
|
|
||||||
blobfd1 = -1; */
|
|
||||||
stable = -1;
|
stable = -1;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,6 @@ const byte * getUpdateArgs(const LogEntry * ret) {
|
||||||
const byte * getUpdatePreImage(const LogEntry * ret) {
|
const byte * getUpdatePreImage(const LogEntry * ret) {
|
||||||
assert(ret->type == UPDATELOG);
|
assert(ret->type == UPDATELOG);
|
||||||
if(operationsTable[ret->contents.update.funcID].undo != NO_INVERSE) {
|
if(operationsTable[ret->contents.update.funcID].undo != NO_INVERSE) {
|
||||||
/* if(ret->contents.update.invertible) { */
|
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
return ((byte*)ret) + sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + ret->contents.update.argSize;
|
return ((byte*)ret) + sizeof(struct __raw_log_entry) + sizeof(UpdateLogEntry) + ret->contents.update.argSize;
|
||||||
|
@ -86,7 +85,6 @@ LogEntry * allocUpdateLogEntry(lsn_t prevLSN, int xid,
|
||||||
ret->xid = xid;
|
ret->xid = xid;
|
||||||
ret->type = UPDATELOG;
|
ret->type = UPDATELOG;
|
||||||
ret->contents.update.funcID = funcID;
|
ret->contents.update.funcID = funcID;
|
||||||
/* ret->contents.update.invertible = invertible; */
|
|
||||||
ret->contents.update.rid = rid;
|
ret->contents.update.rid = rid;
|
||||||
ret->contents.update.argSize = argSize;
|
ret->contents.update.argSize = argSize;
|
||||||
|
|
||||||
|
|
|
@ -188,16 +188,3 @@ LogEntry * readLSNEntry(lsn_t LSN) {
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*lsn_t nextLSN() {
|
|
||||||
lsn_t orig_pos = ftell(log);
|
|
||||||
lsn_t ret;
|
|
||||||
|
|
||||||
fseek(log, 0, SEEK_END);
|
|
||||||
|
|
||||||
ret = ftell(log);
|
|
||||||
|
|
||||||
fseek(log, orig_pos, SEEK_SET);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}*/
|
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
|
|
||||||
/*****************
|
|
||||||
* @file
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* C implementation of logger.h
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @see logger2.c
|
|
||||||
******************/
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <lladd/transactional.h>
|
|
||||||
#include <lladd/logger.h>
|
|
||||||
#include "logparser.h"
|
|
||||||
#include "logstreamer.h"
|
|
||||||
#include <lladd/bufferManager.h>
|
|
||||||
|
|
||||||
static long LogCommonWriterNoExtra(long prevLSN, int xid, int type); /*defined later*/
|
|
||||||
|
|
||||||
long LogTransBegin(Transaction t) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* jason please review and delete comment when done
|
|
||||||
* to recover: pageRalloc(loadPage(rid.page), rid.size)
|
|
||||||
*/
|
|
||||||
long LogTransAlloc(long prevLSN, int xid, recordid rid) {
|
|
||||||
char *extra;
|
|
||||||
int sizeOfExtra = allocPartsToString(&extra, rid);
|
|
||||||
return writeNewLog(prevLSN, xid, XALLOC, extra, sizeOfExtra);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
long LogTransCommit(long prevLSN, int xid) {
|
|
||||||
long newLSN = LogCommonWriterNoExtra(prevLSN, xid, XCOMMIT);
|
|
||||||
flushLog();
|
|
||||||
return newLSN;
|
|
||||||
}
|
|
||||||
|
|
||||||
long LogTransAbort(long prevLSN, int xid) {
|
|
||||||
return LogCommonWriterNoExtra(prevLSN, xid, XABORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
long LogUpdate (long prevLSN, int xid, recordid rid, Operation op, const void *args) {
|
|
||||||
char *extra;
|
|
||||||
/* size_t sizeOfData, sizeOfExtra; */
|
|
||||||
int sizeOfData, sizeOfExtra;
|
|
||||||
void *preImage = 0;
|
|
||||||
int invertible;
|
|
||||||
if (op.sizeofData==SIZEOF_RECORD) {
|
|
||||||
/*then get the size of this record */
|
|
||||||
sizeOfData = rid.size;
|
|
||||||
}
|
|
||||||
else sizeOfData = op.sizeofData;
|
|
||||||
/*heck to see if op is invertible */
|
|
||||||
if (op.undo==NO_INVERSE) {
|
|
||||||
invertible = 0;
|
|
||||||
preImage = (void *)malloc(rid.size);
|
|
||||||
readRecord(xid, rid, preImage);
|
|
||||||
}
|
|
||||||
else invertible = 1;
|
|
||||||
/*will put all of the parts special to an update log record into extra */
|
|
||||||
sizeOfExtra = updatePartsToString(&extra, op.id, rid, args, sizeOfData, invertible, preImage);
|
|
||||||
/*extra has been malloced, but writeNewLog will free it*/
|
|
||||||
if(preImage) {
|
|
||||||
free(preImage);
|
|
||||||
}
|
|
||||||
return writeNewLog(prevLSN, xid, UPDATELOG, extra, sizeOfExtra);
|
|
||||||
}
|
|
||||||
|
|
||||||
long LogCLR (long prevLSN, int xid, long ulLSN, recordid ulRID, long ulPrevLSN) {
|
|
||||||
#define CLRSIZEOFEXTRA 20
|
|
||||||
char *extra;
|
|
||||||
CLRPartsToString(&extra, ulLSN, ulRID, ulPrevLSN);
|
|
||||||
/*extra has been malloced, but writeNewLog will free it*/
|
|
||||||
return writeNewLog(prevLSN, xid, CLRLOG, extra, CLRSIZEOFEXTRA);
|
|
||||||
}
|
|
||||||
|
|
||||||
long LogEnd (long prevLSN, int xid) {
|
|
||||||
return LogCommonWriterNoExtra(prevLSN, xid, XEND);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
LogCommonWriterNoExtra writes the log record in the log tail when there is no extra data
|
|
||||||
being put in the log record -- a special case, and therefore just calls the more generalized LogCommongWriter
|
|
||||||
*/
|
|
||||||
static long LogCommonWriterNoExtra(long prevLSN, int xid, int type) {
|
|
||||||
return writeNewLog(prevLSN, xid, type, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void logInit() {
|
|
||||||
startLogStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
void logDeinit() {
|
|
||||||
closeLogStream();
|
|
||||||
/** FOR NOW, don't delete the log stream at the end, even if all transactions
|
|
||||||
* are committed because we want to debug
|
|
||||||
*/
|
|
||||||
/*deleteLogStream();*/
|
|
||||||
}
|
|
|
@ -112,7 +112,7 @@ LogEntry * LogUpdate(TransactionLog * l, recordid rid, int operation, const byte
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsn_t LogCLR(/*TransactionLog * l,*/ LogEntry * undone) {
|
lsn_t LogCLR(LogEntry * undone) {
|
||||||
lsn_t ret;
|
lsn_t ret;
|
||||||
LogEntry * e = allocCLRLogEntry(-1, undone->xid, undone->LSN, undone->contents.update.rid, undone->prevLSN);
|
LogEntry * e = allocCLRLogEntry(-1, undone->xid, undone->LSN, undone->contents.update.rid, undone->prevLSN);
|
||||||
writeLogEntry(e);
|
writeLogEntry(e);
|
||||||
|
|
|
@ -1,316 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
/*****************
|
|
||||||
* @file
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* corresponding C file of the log parser
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @see logEntry.c
|
|
||||||
* *************/
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "logparser.h"
|
|
||||||
#include "logstreamer.h"
|
|
||||||
|
|
||||||
static CommonLog assembleLog (long prevLSN, int xid, int type, void *extra, int extraLength);
|
|
||||||
static void writeCommonLog (CommonLog comLog);
|
|
||||||
static UpdateLog assembleUpdateLog (int funcID, recordid rid, const void *args, int arglen, int invertible, const void *preimage);
|
|
||||||
static CLRLog assembleCLRLog (long thisUpdateLSN, recordid rid, long undoNextLSN);
|
|
||||||
static int updateLogToString (char **s, UpdateLog upLog);
|
|
||||||
static int CLRLogToString (char **s, CLRLog clrlog);
|
|
||||||
long writeNewLog (long prevLSN, int xid, int type, char *extra, int extraLength) {
|
|
||||||
long thisLSN = writeStreamPos();
|
|
||||||
CommonLog tmpLog;
|
|
||||||
/* printf("LogType:%d\n", type); */
|
|
||||||
tmpLog = assembleLog(prevLSN, xid, type, extra, extraLength);
|
|
||||||
writeCommonLog (tmpLog);
|
|
||||||
if (tmpLog.extraData !=0)
|
|
||||||
free(tmpLog.extraData ); /*free up any malloc'ed string if it is there*/
|
|
||||||
if (extra != 0)
|
|
||||||
free(extra); /*free up extra space that might have been malloced previously*/
|
|
||||||
return thisLSN;
|
|
||||||
}
|
|
||||||
|
|
||||||
int updatePartsToString (char **buf, int funcID, recordid rid, const char *args, int arglen, int invertible, const void *preImage) {
|
|
||||||
UpdateLog ul;
|
|
||||||
int sizeOfString;
|
|
||||||
ul = assembleUpdateLog(funcID, rid, args, arglen, invertible, preImage);
|
|
||||||
sizeOfString = updateLogToString(buf, ul);
|
|
||||||
/* if (ul.args!=0)
|
|
||||||
free(ul.args); //deallocate the update log's arg string that was malloc'ed in assembleUpdateLog (assembleupdate log no longer mallocs. )
|
|
||||||
if (!invertible)
|
|
||||||
free(ul.preImage); */
|
|
||||||
return sizeOfString;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLRPartsToString (char **txt, long thisUpdateLSN, recordid rid, long undoNextLSN) {
|
|
||||||
return CLRLogToString(txt, assembleCLRLog(thisUpdateLSN, rid, undoNextLSN));
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonLog readNextCommonLog() {
|
|
||||||
return readCommonLogFromLSN(readPos());
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonLog readCommonLogFromLSN(long LSN) {
|
|
||||||
byte * buf;/* char *buf;*/
|
|
||||||
long junk;
|
|
||||||
int bufPos, numObjs, extraSize;
|
|
||||||
CommonLog commonStuff;
|
|
||||||
commonStuff.LSN = LSN;
|
|
||||||
commonStuff.type = 0;
|
|
||||||
/*seekandreadlog will allocate space for buffer */
|
|
||||||
junk = seekAndReadLog(LSN, &buf);
|
|
||||||
if (junk==0) {
|
|
||||||
commonStuff.valid=0;
|
|
||||||
free(buf);
|
|
||||||
return commonStuff;
|
|
||||||
}
|
|
||||||
numObjs = sscanf ((char*)buf, "%ld %d %d", &(commonStuff.prevLSN), &(commonStuff.xid), &(commonStuff.type));
|
|
||||||
|
|
||||||
if (numObjs!=3) {
|
|
||||||
commonStuff.valid = 0;
|
|
||||||
free(buf);
|
|
||||||
return commonStuff; /*if we don't have the 3 basic ingredients, invalid log entry or at end of file, etc*/
|
|
||||||
}
|
|
||||||
commonStuff.valid = 1;
|
|
||||||
/*try to read extra data, if possible (will first have a size in bytes of the future data)
|
|
||||||
check if there is data beyond the 3 fields for optional data, and if so note where to put the data in buf*/
|
|
||||||
if (sscanf((char*)buf, "%ld %*d %*d %d %n", &junk, &extraSize, &bufPos)==2) { /*note: pos does not increase the object count of sscanf*/
|
|
||||||
/*then there is an extra string*/
|
|
||||||
commonStuff.extraData = (void*)malloc(extraSize);
|
|
||||||
commonStuff.extraDataSize = extraSize;
|
|
||||||
memcpy(commonStuff.extraData, buf+bufPos, extraSize);
|
|
||||||
/*printf ("reading extradata=%d %d; extrasize=%d, bufpos=%d\n", *(int *)commonStuff.extraData, *(int *)(commonStuff.extraData+4), extraSize, bufPos);*/
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
commonStuff.extraData = NULL;
|
|
||||||
commonStuff.extraDataSize = 0;
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
return commonStuff;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateLog updateStringToParts(byte *txt) {
|
|
||||||
UpdateLog thisUpdate;
|
|
||||||
int txtPos;
|
|
||||||
long int tmp_size;
|
|
||||||
/*read in the fixed size parts and get the position of where the data begins*/
|
|
||||||
sscanf ((char*)txt, "%d %d %d %ld %d %d%n", &(thisUpdate.funcID), &(thisUpdate.rid.page),
|
|
||||||
&(thisUpdate.rid.slot), &tmp_size,/*(thisUpdate.rid.size),*/ &(thisUpdate.invertible), &thisUpdate.argSize, &txtPos);
|
|
||||||
thisUpdate.rid.size = (size_t) tmp_size;
|
|
||||||
txtPos++; /*there is an additional space between the argSize and the arg data*/
|
|
||||||
thisUpdate.args = (void*)malloc(thisUpdate.argSize);
|
|
||||||
memcpy((byte*)thisUpdate.args, txt+txtPos, thisUpdate.argSize);
|
|
||||||
txtPos += 1+thisUpdate.argSize;
|
|
||||||
if (!thisUpdate.invertible) {
|
|
||||||
thisUpdate.preImage = (void*)malloc(thisUpdate.rid.size);
|
|
||||||
/* Remove the const qualifier from preImage so that we can initialize the malloced memory. */
|
|
||||||
memcpy((void*)thisUpdate.preImage, txt+txtPos, thisUpdate.rid.size);
|
|
||||||
}
|
|
||||||
return thisUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLRLog CLRStringToParts (void *txt) {
|
|
||||||
CLRLog clrlog;
|
|
||||||
long int size_tmp;
|
|
||||||
sscanf(txt, "%ld %d %d %ld %ld", &(clrlog.thisUpdateLSN), &(clrlog.rid.page), &(clrlog.rid.slot), &(size_tmp), &(clrlog.undoNextLSN));
|
|
||||||
clrlog.rid.size = (size_t) size_tmp;
|
|
||||||
return clrlog;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Fix string buffer size!!! */
|
|
||||||
int allocPartsToString (char **txt, recordid rid) {
|
|
||||||
|
|
||||||
return asprintf(txt, "%d %d %ld", rid.page, rid.slot, (long int)rid.size);
|
|
||||||
/* *txt = malloc(2*sizeof(int)+sizeof(long)+200);
|
|
||||||
sprintf (*txt, "%d %d %ld", rid.page, rid.slot, rid.size); */
|
|
||||||
/*memcpy(txt, &rid, sizeof(recordid));
|
|
||||||
printf ("writing rid=%d,%d,%ld\n", rid.page, rid.slot, rid.size);*/
|
|
||||||
/*return sizeof(recordid);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
recordid allocStringToRID (void *txt) {
|
|
||||||
recordid tmp;
|
|
||||||
long int tmp2;
|
|
||||||
sscanf(txt, "%d %d %ld", &tmp.page, &tmp.slot, &tmp2);
|
|
||||||
tmp.size = (size_t)tmp2;
|
|
||||||
/*memcpy(&tmp, txt, sizeof(recordid));
|
|
||||||
printf ("reading rid=%d,%d,%ld\n", tmp.page, tmp.slot, tmp.size);*/
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/************ PRIVATE WRITING-RELATED FUNCTIONS ********************/
|
|
||||||
/*
|
|
||||||
put the pieces of a complete (common) log into the structure
|
|
||||||
*/
|
|
||||||
static CommonLog assembleLog (long prevLSN, int xid, int type, void *extra, int extraLength) {
|
|
||||||
CommonLog tmp;
|
|
||||||
tmp.prevLSN = prevLSN;
|
|
||||||
tmp.xid = xid;
|
|
||||||
tmp.type = type;
|
|
||||||
tmp.valid = 1;
|
|
||||||
tmp.extraDataSize = extraLength;
|
|
||||||
if (extraLength==0)
|
|
||||||
tmp.extraData = NULL;
|
|
||||||
else {
|
|
||||||
tmp.extraData = (void*)malloc(extraLength);
|
|
||||||
memcpy(tmp.extraData, extra, extraLength);
|
|
||||||
}
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
marshal an common log into the log file
|
|
||||||
*/
|
|
||||||
static void writeCommonLog (CommonLog comLog) {
|
|
||||||
char *buf;
|
|
||||||
int bytesWritten;
|
|
||||||
if (comLog.extraDataSize==0) {
|
|
||||||
/*TODO: Fix buffer size! (Throughout file) */
|
|
||||||
/* buf = malloc(2*sizeof(int)+sizeof(long)+200); */
|
|
||||||
bytesWritten = asprintf (&buf, "%ld %d %d", comLog.prevLSN, comLog.xid, comLog.type);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char * buf2;
|
|
||||||
/* buf = malloc(3*sizeof(int)+sizeof(long)+200+4+comLog.extraDataSize); */
|
|
||||||
/*first print all the ordinary components plus a space, then size of extra; note the last byte put into sprintf*/
|
|
||||||
bytesWritten = asprintf (&buf, "%ld %d %d %d ", comLog.prevLSN, comLog.xid, comLog.type, comLog.extraDataSize);
|
|
||||||
buf2 = malloc(bytesWritten + comLog.extraDataSize);
|
|
||||||
memcpy (buf2, buf, bytesWritten);
|
|
||||||
free(buf);
|
|
||||||
buf = buf2;
|
|
||||||
/*directly write the data into the buffer after the rest of the stuff*/
|
|
||||||
memcpy (buf+bytesWritten, comLog.extraData, comLog.extraDataSize);
|
|
||||||
/*printf("writing extra=%d %d\n", *(int *)comLog.extraData, *(int *)(comLog.extraData+4));*/
|
|
||||||
}
|
|
||||||
writeLog(buf, bytesWritten+comLog.extraDataSize);
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Given all the components of an update log, will produce an update log
|
|
||||||
|
|
||||||
Returns an UpdateLog
|
|
||||||
NOTE: mallocates the output log's args string, so must be freed after use (Not true any more.)
|
|
||||||
*/
|
|
||||||
static UpdateLog assembleUpdateLog (int funcID, recordid rid, const void *args, int arglen, int invertible, const void *preimage) {
|
|
||||||
UpdateLog tmpLog;
|
|
||||||
tmpLog.funcID = funcID;
|
|
||||||
tmpLog.rid = rid;
|
|
||||||
/* tmpLog.args = (void*)malloc(arglen); */
|
|
||||||
tmpLog.argSize = arglen;
|
|
||||||
tmpLog.invertible = invertible;
|
|
||||||
/* memcpy (tmpLog.args, args, arglen); */
|
|
||||||
|
|
||||||
tmpLog.args = args;
|
|
||||||
|
|
||||||
if (!invertible) {
|
|
||||||
/*Don't need this? Just set the pointer... */
|
|
||||||
/* tmpLog.preImage = (void*)malloc(rid.size);
|
|
||||||
memcpy(tmpLog.preImage, preimage, rid.size); */
|
|
||||||
tmpLog.preImage = preimage;
|
|
||||||
} else {
|
|
||||||
tmpLog.preImage = 0;
|
|
||||||
}
|
|
||||||
return tmpLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CLRLog assembleCLRLog (long thisUpdateLSN, recordid rid, long undoNextLSN) {
|
|
||||||
CLRLog tmpLog;
|
|
||||||
tmpLog.thisUpdateLSN = thisUpdateLSN;
|
|
||||||
tmpLog.rid = rid;
|
|
||||||
tmpLog.undoNextLSN = undoNextLSN;
|
|
||||||
return tmpLog;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
marshal an update log into a string (assume the string space has been allocated)
|
|
||||||
returns number of bytes written to the string
|
|
||||||
*/
|
|
||||||
static int updateLogToString (char **s, UpdateLog upLog) {
|
|
||||||
int bytesWritten;
|
|
||||||
/* int maxDigitsForInt = 25; //32767 is 5 digits, plus a negative
|
|
||||||
int maxDigitsForLong = 25;
|
|
||||||
int estSize = 5*maxDigitsForInt+maxDigitsForLong+6+upLog.argSize;*/
|
|
||||||
|
|
||||||
char *tmp;
|
|
||||||
|
|
||||||
/* if (!upLog.invertible)
|
|
||||||
estSize+=1+upLog.rid.size; */
|
|
||||||
|
|
||||||
|
|
||||||
bytesWritten = asprintf (&tmp, "%d %d %d %ld %d %d ", upLog.funcID, upLog.rid.page, upLog.rid.slot, (long int)upLog.rid.size, upLog.invertible, upLog.argSize);
|
|
||||||
|
|
||||||
*s = malloc(bytesWritten + upLog.argSize);
|
|
||||||
memcpy(*s, tmp, bytesWritten);
|
|
||||||
free (tmp);
|
|
||||||
memcpy(*s+bytesWritten, upLog.args, upLog.argSize);
|
|
||||||
bytesWritten+=upLog.argSize;
|
|
||||||
if (!upLog.invertible) {
|
|
||||||
tmp = *s;
|
|
||||||
*s = malloc(bytesWritten+1 +upLog.rid.size);
|
|
||||||
memcpy(*s, tmp, bytesWritten);
|
|
||||||
free (tmp);
|
|
||||||
|
|
||||||
sprintf (*s+bytesWritten, " ");
|
|
||||||
memcpy(*s+bytesWritten+1, upLog.preImage, upLog.rid.size);
|
|
||||||
bytesWritten += 1 + upLog.rid.size;
|
|
||||||
}
|
|
||||||
return bytesWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CLRLogToString (char **s, CLRLog clrlog) {
|
|
||||||
/* int estSize = 3*sizeof(long)+2*sizeof(int)+400; */
|
|
||||||
int bytesWritten;
|
|
||||||
/* *s = malloc(estSize); */
|
|
||||||
bytesWritten = asprintf (s, "%ld %d %d %ld %ld ", clrlog.thisUpdateLSN, clrlog.rid.page, clrlog.rid.slot, (long int)clrlog.rid.size, clrlog.undoNextLSN);
|
|
||||||
/* if (bytesWritten!=estSize) {
|
|
||||||
//error!
|
|
||||||
}*/
|
|
||||||
return bytesWritten;
|
|
||||||
}
|
|
|
@ -1,206 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
*
|
|
||||||
* logparser implements the specific formats of the log entrys to be read and
|
|
||||||
* written in the log file.
|
|
||||||
*
|
|
||||||
* All log entries have some fields in common (always) - a previous LSN, a
|
|
||||||
* transaction id, a log type, and any extra text specific to the type of entry.
|
|
||||||
* The extra text may be NULL, in which case there is no extra text! If there is
|
|
||||||
* extra text, additional public functions are written to put together and take
|
|
||||||
* apart the string into its object.
|
|
||||||
*
|
|
||||||
* This has been entirely rewritten. Don't use it.
|
|
||||||
*
|
|
||||||
* @deprecated @see logEntry.h
|
|
||||||
*
|
|
||||||
* Proposed api:
|
|
||||||
|
|
||||||
|
|
||||||
All of these return a pointer to a single malloced region that should be freed.
|
|
||||||
|
|
||||||
allocCommonLogEntry(LSN, prevLSN, xid, type);
|
|
||||||
allocUpdateLogEntry(LSN, prevLSN, xid, type=UPDATE, funcID, rid, args, argSize, preImage);
|
|
||||||
allocCLRLogEntry (LSN, prevLSN, xid, type=CLR, thisUpdateLSN, rid, undoNextLSN);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
thisUpdateLSN;
|
|
||||||
rid;
|
|
||||||
undoNextLSN;
|
|
||||||
} CLRLogEntry;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
funcID;
|
|
||||||
rid;
|
|
||||||
argSize;
|
|
||||||
/ * Implicit members:
|
|
||||||
args; @ ((byte*)ule) + sizeof(UpdateLogEntry)
|
|
||||||
preImage; @ ((byte*)ule) + sizeof(UpdateLogEntry) + ule.argSize * /
|
|
||||||
} UpdateLogEntry;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
LSN;
|
|
||||||
prevLSN;
|
|
||||||
xid;
|
|
||||||
type;
|
|
||||||
union {
|
|
||||||
UpdateLogEntry update;
|
|
||||||
CLRLogEntry clr;
|
|
||||||
} contents;
|
|
||||||
} LogEntry;
|
|
||||||
|
|
||||||
sizeofLogEntry(LogEntry *);
|
|
||||||
size_t getUpdateArgs(LogEntry *);
|
|
||||||
size_t getUpdatePreImage(LogEntry *);
|
|
||||||
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef __LOGPARSER_H__
|
|
||||||
#define __LOGPARSER_H__
|
|
||||||
|
|
||||||
#include <lladd/page.h>
|
|
||||||
#include <lladd/constants.h>
|
|
||||||
|
|
||||||
/* max the log line can be is 2 pages (set redo and undo data possibly) plus
|
|
||||||
* some more log stuff */
|
|
||||||
/*#define maxLogLineLength 2*PAGE_SIZE + 100 */
|
|
||||||
|
|
||||||
/*
|
|
||||||
fields common to all log entries
|
|
||||||
extra could be null, indicating no extra data needed
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
/**LSN field is ignored when writing to log, since it is determined
|
|
||||||
by the writer */
|
|
||||||
long LSN;
|
|
||||||
long prevLSN;
|
|
||||||
int xid;
|
|
||||||
int type;
|
|
||||||
void *extraData;
|
|
||||||
int extraDataSize;
|
|
||||||
int valid;
|
|
||||||
} CommonLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Update Log components (that are normally stored in the 'extra' field of a common log
|
|
||||||
|
|
||||||
The preimage is used for undos of operations with no inverses, and
|
|
||||||
the args field is used for the redo process, and inverse functions.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
/**what function it is*/
|
|
||||||
int funcID;
|
|
||||||
/**page and slot number*/
|
|
||||||
recordid rid;
|
|
||||||
/**binary data of the function arguments*/
|
|
||||||
const byte *args;
|
|
||||||
int argSize;
|
|
||||||
int invertible;
|
|
||||||
/**if funcID is not invertible will store a preImage with size=rid.size*/
|
|
||||||
const byte *preImage;
|
|
||||||
} UpdateLog;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* UpdateLog ul; //has everything in an update log */
|
|
||||||
long thisUpdateLSN;
|
|
||||||
recordid rid;
|
|
||||||
long undoNextLSN;
|
|
||||||
} CLRLog;
|
|
||||||
|
|
||||||
|
|
||||||
/********* PUBLIC WRITING-RELATED FUNCTIONS **************/
|
|
||||||
/**
|
|
||||||
Given all the necessary components of a log entry, assemble it and then write it to the log file
|
|
||||||
|
|
||||||
return the LSN of this new log entry
|
|
||||||
|
|
||||||
*/
|
|
||||||
long writeNewLog (long prevLSN, int xid, int type, char *extra, int extraLength);
|
|
||||||
|
|
||||||
/**
|
|
||||||
put all of the components of the extra part of an update log into a buffer
|
|
||||||
returns the length of the string written to buf
|
|
||||||
|
|
||||||
@ todo Logparser shouldn't write to char**
|
|
||||||
*/
|
|
||||||
int updatePartsToString (char **buf, int funcID, recordid rid, const char *args, int arglen, int invertible, const void *preImage);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Takes in a buffer and a record id and copies the recordid into the buffer
|
|
||||||
*/
|
|
||||||
int allocPartsToString (char **txt, recordid rid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
*/
|
|
||||||
int CLRPartsToString (char **txt, long thisUpdateLSN, recordid rid, long undoNextLSN);
|
|
||||||
/********* PUBLIC READING-RELATED FUNCTIONS **************/
|
|
||||||
/**
|
|
||||||
parse a log line that only parses entries common to all log records into its structure. Can specify an LSN
|
|
||||||
|
|
||||||
NOTE: the extra part of CommonLog might have a malloc'ed string in it; should be freed after use
|
|
||||||
*/
|
|
||||||
CommonLog readNextCommonLog();
|
|
||||||
CommonLog readCommonLogFromLSN(long LSN);
|
|
||||||
|
|
||||||
|
|
||||||
CLRLog readCLRLogFromLSN(long LSN);
|
|
||||||
/**
|
|
||||||
parse the extra part of an update log record into an UpdateLog structure
|
|
||||||
|
|
||||||
NOTE: the args part of the UpdateLog has a malloc'ed string in it; should be freed after use
|
|
||||||
*/
|
|
||||||
UpdateLog updateStringToParts(byte *txt);
|
|
||||||
|
|
||||||
CLRLog CLRStringToParts (void *txt);
|
|
||||||
/**
|
|
||||||
Read a buffer and parse it into a recordid
|
|
||||||
*/
|
|
||||||
recordid allocStringToRID (void *txt);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,148 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
/*****************
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
the C implementation of logstreamer.h
|
|
||||||
******************/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include <lladd/constants.h>
|
|
||||||
#include "logstreamer.h"
|
|
||||||
|
|
||||||
static FILE *log;
|
|
||||||
|
|
||||||
int startLogStream() {
|
|
||||||
log = fopen(LOG_FILE, "a+");
|
|
||||||
if (log==NULL) {
|
|
||||||
/*there was an error opening this file */
|
|
||||||
return FILE_WRITE_OPEN_ERROR;
|
|
||||||
}
|
|
||||||
/*if file is empty, write a null at the 0th character */
|
|
||||||
if (streamPos()==0)
|
|
||||||
fputs("0", log);
|
|
||||||
/*start reading at the 1st character*/
|
|
||||||
fseek(log, 1, SEEK_SET);
|
|
||||||
return 0; /*otherwise return 0 for no errors*/
|
|
||||||
}
|
|
||||||
|
|
||||||
int writeLog(void *s, int length) {
|
|
||||||
/* int i; */
|
|
||||||
fprintf(log, "%d ", length); /*print out the size of this log entry (not including this item and the \n */
|
|
||||||
|
|
||||||
if(1 != fwrite(s, length, 1, log)) {
|
|
||||||
|
|
||||||
/* for( i = 0; i < length; i++ ) {
|
|
||||||
if(fputc(*(char*)(s+i), log) == EOF) { //write the string to the log tail*/
|
|
||||||
perror("logstreamer: fputc");
|
|
||||||
assert(0);
|
|
||||||
/* } */
|
|
||||||
}
|
|
||||||
fprintf (log, "\n"); /*then write a carriage return just for our viewing pleasure*/
|
|
||||||
return 0; /*otherwise, no errors*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void flushLog() {
|
|
||||||
fflush(log);
|
|
||||||
/* fsync(fileno(log)); */
|
|
||||||
fdatasync(fileno(log));
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeLogStream() {
|
|
||||||
fclose(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteLogStream() {
|
|
||||||
remove(LOG_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
long streamPos() {
|
|
||||||
return ftell(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Assumes we're already @ EOF. */
|
|
||||||
long writeStreamPos() {
|
|
||||||
/* long cur = ftell(log);
|
|
||||||
fseek(log, 0, SEEK_END);
|
|
||||||
assert(cur == ftell(log));*/
|
|
||||||
return ftell(log);
|
|
||||||
/* long curPos = streamPos();
|
|
||||||
long returnVal;
|
|
||||||
fseek(log, 0, SEEK_END);
|
|
||||||
returnVal = ftell(log);
|
|
||||||
fseek(log, curPos, SEEK_SET);
|
|
||||||
return returnVal;*/
|
|
||||||
}
|
|
||||||
int readLog(byte **buffer) {
|
|
||||||
int length, i;
|
|
||||||
*buffer = 0;
|
|
||||||
if (feof(log)) return 0;
|
|
||||||
fscanf(log, "%d ", &length);
|
|
||||||
if (feof(log)) return 0;
|
|
||||||
/*get length characters from the log at this point and put them
|
|
||||||
into the buffer */
|
|
||||||
*buffer = malloc(length+5); /*5 extra just to be safe*/
|
|
||||||
for (i=0; i<length; i++)
|
|
||||||
*(char*)(*buffer+i) = fgetc(log);
|
|
||||||
/*experiment: null terminate the buffer to avoid read leaks over the memory just in case */
|
|
||||||
*(char*)(*buffer+i) = '\0';
|
|
||||||
/*then read in the newline that was put in to be nice */
|
|
||||||
fgetc(log);
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int seekAndReadLog(long pos, byte **buffer) {
|
|
||||||
fseek(log, pos, 0); /*seek to pos positions from the beginning of the file*/
|
|
||||||
return readLog(buffer);
|
|
||||||
}
|
|
||||||
void seekInLog(long pos) {
|
|
||||||
fseek(log, pos, 0);
|
|
||||||
}
|
|
||||||
long readPos () {
|
|
||||||
return ftell(log);
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
/** ***************
|
|
||||||
* @file
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* logstreamer is the implementation of writing the log tail
|
|
||||||
* It must be bufferred -- in that when something is written to the log tail it
|
|
||||||
* is not immediately written to disk, but rather just ot memory. But
|
|
||||||
* logstreamer must be able to force flush to disk, which will be done when a
|
|
||||||
* commit log entry is written to the log tail
|
|
||||||
*
|
|
||||||
* Note: using the stdio FILEs for this, and by default it is "fully" buffered.
|
|
||||||
* The log tail may be flushed to disk without an explicit call to fflush (when
|
|
||||||
* the program terminates, the file closes), but this is acceptable because it
|
|
||||||
* never hurts to have more flushes to disk, as long as it doesn't hurt
|
|
||||||
* performance.
|
|
||||||
*
|
|
||||||
* @deprecated @see logWriter.h logHandle.h
|
|
||||||
*
|
|
||||||
* *************/
|
|
||||||
|
|
||||||
#ifndef __LOGSTREAMER_H__
|
|
||||||
#define __LOGSTREAMER_H__
|
|
||||||
|
|
||||||
#include <lladd/constants.h>
|
|
||||||
#include <lladd/common.h>
|
|
||||||
/*
|
|
||||||
start a new log stream by opening the log file for reading
|
|
||||||
|
|
||||||
returns 0 on success, or an error code define above
|
|
||||||
*/
|
|
||||||
int startLogStream();
|
|
||||||
|
|
||||||
/*
|
|
||||||
passed an address with data in it, writes it out to the log tail (not yet
|
|
||||||
flushed)
|
|
||||||
|
|
||||||
returns 0 on success, or an error code defined above
|
|
||||||
*/
|
|
||||||
int writeLog(void *s, int length);
|
|
||||||
|
|
||||||
/*
|
|
||||||
flush the entire log (tail) that is currently in memory to disk
|
|
||||||
*/
|
|
||||||
void flushLog();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Close the log stream
|
|
||||||
*/
|
|
||||||
void closeLogStream();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the current position of the stream (in terms of bytes)
|
|
||||||
*/
|
|
||||||
long getFilePos();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Actually deletes the log file that may have been written to disk! Danger!!
|
|
||||||
Only use after calling closeLogStream AND you are sure there are no active (or
|
|
||||||
future active) transactions!
|
|
||||||
*/
|
|
||||||
void deleteLogStream();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the current position of the stream no matter where it is
|
|
||||||
*/
|
|
||||||
long streamPos();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the position of the stream if it were to read.
|
|
||||||
*/
|
|
||||||
long writeStreamPos();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* readLog reads a line from the log puts it in a string
|
|
||||||
*
|
|
||||||
* returns the number of bytes read and put into buffer
|
|
||||||
* */
|
|
||||||
int readLog(byte **buffer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* seek to a position in the log file and read it into the buffer
|
|
||||||
*
|
|
||||||
* returns the number of bytes read and put into buffer
|
|
||||||
* */
|
|
||||||
int seekAndReadLog(long pos, byte **buffer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* tell the current position in the log file
|
|
||||||
* */
|
|
||||||
long readPos ();
|
|
||||||
|
|
||||||
void seekInLog(long pos);
|
|
||||||
#endif
|
|
|
@ -14,7 +14,8 @@
|
||||||
@todo Currently, if the system crashes during an alloc, (before the
|
@todo Currently, if the system crashes during an alloc, (before the
|
||||||
log is flushed, but after bufferManager returns a rid), then the
|
log is flushed, but after bufferManager returns a rid), then the
|
||||||
space alloced during the crash is leaked. This doesn't seem to be
|
space alloced during the crash is leaked. This doesn't seem to be
|
||||||
too big of a deal, but it should be fixed someday.
|
too big of a deal, but it should be fixed someday. A more serious
|
||||||
|
problem results from crashes during blob allocation.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -59,6 +60,10 @@ recordid Talloc(int xid, size_t size) {
|
||||||
problem involving blob allocation, which is more serious, as it may
|
problem involving blob allocation, which is more serious, as it may
|
||||||
result in double allocation...)
|
result in double allocation...)
|
||||||
|
|
||||||
|
@todo If this should be the only call to ralloc in lladd, we may consider
|
||||||
|
removing the lsn parameter someday. (Is there a good reason to
|
||||||
|
provide users with direct access to ralloc()?)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rid = ralloc(xid, -1, size);
|
rid = ralloc(xid, -1, size);
|
||||||
|
|
|
@ -47,7 +47,6 @@ terms specified in this license.
|
||||||
**********************************************/
|
**********************************************/
|
||||||
|
|
||||||
#include <lladd/operations/prepare.h>
|
#include <lladd/operations/prepare.h>
|
||||||
/*#include "../logger/logstreamer.h"*/
|
|
||||||
#include <lladd/logger/logWriter.h>
|
#include <lladd/logger/logWriter.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
|
@ -57,37 +56,17 @@ static int operate(int xid, recordid rid, const void *dat) {
|
||||||
syncLog();
|
syncLog();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*static int no_op(int xid, recordid rid, const void *dat) {
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
Tprepare notes:
|
|
||||||
|
|
||||||
- Just a Tupdate, with a log flush as its operationsTable[]
|
|
||||||
function. (done)
|
|
||||||
|
|
||||||
- After recovery, all of the xacts pages will have been 'stolen',
|
|
||||||
(if recovery flushes dirty pages) (done)
|
|
||||||
|
|
||||||
- Recovery function needs to distinguish between actions before and
|
|
||||||
after the last Tprepare log entry.
|
|
||||||
|
|
||||||
- The switch in recovUndo needs to treat Tprepares as follows:
|
|
||||||
|
|
||||||
- If we're really doing recovery, don't push the prevLSN onto
|
|
||||||
transRecLSN's. Instead, add it to the active transaction table
|
|
||||||
in transactional.c
|
|
||||||
|
|
||||||
- If not, do nothing, but push the prevLSN onto transRecLSN's
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Operation getPrepare() {
|
Operation getPrepare() {
|
||||||
Operation o = {
|
Operation o = {
|
||||||
OPERATION_PREPARE, /* id */
|
OPERATION_PREPARE, /* id */
|
||||||
0, /* No extra data. */
|
0, /* No extra data. */
|
||||||
OPERATION_PREPARE, /*&no_op,*/ /* Otherwise, it will need to store a pre-image of something... */
|
OPERATION_PREPARE, /* If we set this to NO_INVERSE, it
|
||||||
|
will needlessly store a
|
||||||
|
pre-image of something... since
|
||||||
|
OPERATION_PREPARE just performs
|
||||||
|
a log flush, calling it during
|
||||||
|
redo is harmless. */
|
||||||
&operate /* Function */
|
&operate /* Function */
|
||||||
};
|
};
|
||||||
return o;
|
return o;
|
||||||
|
|
306
src/lladd/page.c
306
src/lladd/page.c
|
@ -135,10 +135,6 @@ void pageDeRalloc(Page page, recordid rid);
|
||||||
|
|
||||||
void pageCompact(Page page);
|
void pageCompact(Page page);
|
||||||
|
|
||||||
touchedBlob_t *touched;
|
|
||||||
size_t touchedLen;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pageInit() initializes all the important variables needed in
|
* pageInit() initializes all the important variables needed in
|
||||||
* all the functions dealing with pages.
|
* all the functions dealing with pages.
|
||||||
|
@ -173,90 +169,8 @@ void pageInit() {
|
||||||
MASK_0000FFFF = (1 << (2*BITS_PER_BYTE)) - 1;
|
MASK_0000FFFF = (1 << (2*BITS_PER_BYTE)) - 1;
|
||||||
MASK_FFFF0000 = ~MASK_0000FFFF;
|
MASK_FFFF0000 = ~MASK_0000FFFF;
|
||||||
|
|
||||||
touchedLen = DEFAULT_TOUCHED;
|
|
||||||
touched = calloc(touchedLen, sizeof(touchedBlob_t));
|
|
||||||
|
|
||||||
/* if( (blob_0_fd = open(BLOB0_FILE, O_RDWR, 0)) == -1 ) {
|
|
||||||
perror("page.c:opening blob file 0");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
if( (blob_1_fd = open(BLOB1_FILE, O_RDWR, 0)) == -1 ) {
|
|
||||||
perror("page.c:opening blob file 1");
|
|
||||||
exit(-1);
|
|
||||||
} */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rehashTouch() {
|
|
||||||
|
|
||||||
int i;
|
|
||||||
touchedBlob_t *touched_old = touched;
|
|
||||||
touchedLen *= 2;
|
|
||||||
touched = calloc(touchedLen, sizeof(touchedBlob_t));
|
|
||||||
assert(touched);
|
|
||||||
|
|
||||||
for( i = 0; i < touchedLen/2; i++ ) {
|
|
||||||
if( touched_old[i].records ) {
|
|
||||||
touched[touched_old[i].xid%touchedLen] = touched_old[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(touched_old);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int touchBlob(int xid, recordid rid) {
|
|
||||||
|
|
||||||
touchedBlob_t *t = &touched[xid%touchedLen];
|
|
||||||
if( t->records ) {
|
|
||||||
if( t->xid == xid ) {
|
|
||||||
recordid ret = t->records[(rid.page+rid.slot)%t->len];
|
|
||||||
if( ret.size ) {
|
|
||||||
if( ret.page == rid.page && ret.slot == rid.slot ) {
|
|
||||||
return 1;
|
|
||||||
} else { /* there's another entry for this space */
|
|
||||||
int i;
|
|
||||||
recordid *old = t->records;
|
|
||||||
t->len *= 2;
|
|
||||||
t->records = calloc(t->len, sizeof(recordid));
|
|
||||||
for( i = 0; i < t->len/2; i++ ) {
|
|
||||||
if( old[i].size ) {
|
|
||||||
t->records[ (old[i].page+old[i].slot) % t->len ] = old[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return touchBlob(xid, rid);
|
|
||||||
}
|
|
||||||
} else { /* space is free, mark it */
|
|
||||||
t->records[(rid.page+rid.slot)%t->len] = rid;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else { /* this is not our transaction */
|
|
||||||
do {
|
|
||||||
rehashTouch();
|
|
||||||
} while( touchBlob(xid, rid) );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else { /* we haven't allocated for this xid */
|
|
||||||
t->records = calloc(DEFAULT_TOUCHED, sizeof(recordid));
|
|
||||||
t->records[(rid.page+rid.slot)%DEFAULT_TOUCHED] = rid;
|
|
||||||
t->len = DEFAULT_TOUCHED;
|
|
||||||
t->xid = xid;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static void rmTouch(int xid) {
|
|
||||||
|
|
||||||
touchedBlob_t *t = &touched[xid%touchedLen];
|
|
||||||
if( t ) {
|
|
||||||
free( t->records );
|
|
||||||
t->records = NULL;
|
|
||||||
/ * touched[xid%touchedLen].xid = -1; TODO: necessary? * /
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void pageCommit(int xid) {
|
void pageCommit(int xid) {
|
||||||
/* rmTouch(xid); */
|
/* rmTouch(xid); */
|
||||||
}
|
}
|
||||||
|
@ -265,8 +179,6 @@ void pageAbort(int xid) {
|
||||||
/* rmTouch(xid); */
|
/* rmTouch(xid); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*#define getFirstHalfOfWord(memAddr) (((*(int*)memAddr) >> (2*BITS_PER_BYTE)) & MASK_0000FFFF) */
|
|
||||||
|
|
||||||
static int getFirstHalfOfWord(unsigned int *memAddr) {
|
static int getFirstHalfOfWord(unsigned int *memAddr) {
|
||||||
unsigned int word = *memAddr;
|
unsigned int word = *memAddr;
|
||||||
word = (word >> (2*BITS_PER_BYTE)); /* & MASK_0000FFFF; */
|
word = (word >> (2*BITS_PER_BYTE)); /* & MASK_0000FFFF; */
|
||||||
|
@ -384,6 +296,8 @@ static void writeNumSlots(byte *memAddr, int numSlots) {
|
||||||
*
|
*
|
||||||
* NOTE: pageRalloc() assumes that the caller already made sure that sufficient
|
* NOTE: pageRalloc() assumes that the caller already made sure that sufficient
|
||||||
* amount of freespace exists in this page. (@see freespace())
|
* amount of freespace exists in this page. (@see freespace())
|
||||||
|
*
|
||||||
|
* @todo Makes no attempt to reuse old recordid's.
|
||||||
*/
|
*/
|
||||||
recordid pageRalloc(Page page, size_t size) {
|
recordid pageRalloc(Page page, size_t size) {
|
||||||
int freeSpace = readFreeSpace(page.memAddr);
|
int freeSpace = readFreeSpace(page.memAddr);
|
||||||
|
@ -393,12 +307,11 @@ recordid pageRalloc(Page page, size_t size) {
|
||||||
rid.page = page.id;
|
rid.page = page.id;
|
||||||
rid.slot = numSlots;
|
rid.slot = numSlots;
|
||||||
rid.size = size;
|
rid.size = size;
|
||||||
/*int i; */
|
|
||||||
|
|
||||||
/* Make sure there's enough free space... */
|
/* Make sure there's enough free space... */
|
||||||
/* assert (freespace(page) >= (int)size); */
|
/* assert (freespace(page) >= (int)size); */ /*Expensive, so skipped not done. */
|
||||||
|
|
||||||
/* Reuse an old (invalid) slot entry */
|
/* Reuse an old (invalid) slot entry. Why was this here? */
|
||||||
/* for (i = 0; i < numSlots; i++) {
|
/* for (i = 0; i < numSlots; i++) {
|
||||||
if (!isValidSlot(page.memAddr, i)) {
|
if (!isValidSlot(page.memAddr, i)) {
|
||||||
rid.slot = i;
|
rid.slot = i;
|
||||||
|
@ -468,12 +381,12 @@ void pageCompact(Page page) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
byte buffer[PAGE_SIZE];
|
byte buffer[PAGE_SIZE];
|
||||||
/* char *buffer = (char *)malloc(PAGE_SIZE); */
|
|
||||||
int freeSpace = 0;
|
int freeSpace = 0;
|
||||||
int numSlots = readNumSlots(page.memAddr);
|
int numSlots = readNumSlots(page.memAddr);
|
||||||
int meta_size = LSN_SIZE + FREE_SPACE_SIZE + NUMSLOTS_SIZE + (SLOT_SIZE*numSlots);
|
int meta_size = LSN_SIZE + FREE_SPACE_SIZE + NUMSLOTS_SIZE + (SLOT_SIZE*numSlots);
|
||||||
int slot_length;
|
int slot_length;
|
||||||
int last_used_slot = 0;
|
int last_used_slot = 0;
|
||||||
|
|
||||||
/* Can't compact in place, slot numbers can come in different orders than
|
/* Can't compact in place, slot numbers can come in different orders than
|
||||||
the physical space allocated to them. */
|
the physical space allocated to them. */
|
||||||
memcpy(buffer + PAGE_SIZE - meta_size, page.memAddr + PAGE_SIZE - meta_size, meta_size);
|
memcpy(buffer + PAGE_SIZE - meta_size, page.memAddr + PAGE_SIZE - meta_size, meta_size);
|
||||||
|
@ -537,163 +450,34 @@ int isBlobSlot(byte *pageMemAddr, int slot) {
|
||||||
return BLOB_SLOT == getSlotLength(pageMemAddr, slot);
|
return BLOB_SLOT == getSlotLength(pageMemAddr, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
Blob format:
|
@todo This needs should trust the rid (since the caller needs to
|
||||||
|
overrid the size in special circumstances, but if the size has been
|
||||||
If the slot entry's size is BLOB_SLOT, then the slot points to a blob record instead of data. The format of this record is:
|
overridden, we should check for the circumstances where doing so is
|
||||||
|
allowed.
|
||||||
Int: Version number (0/1)
|
|
||||||
Int: Archive offset
|
|
||||||
Int: Blob size.
|
|
||||||
|
|
||||||
TODO: BufferManager should pass in file descriptors so that this function doesn't have to open and close the file on each call.
|
|
||||||
|
|
||||||
@todo This needs to trust the rid, which is fine, but it could do more to check if the page agrees with the rid...
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void pageReadRecord(int xid, Page page, recordid rid, byte *buff) {
|
void pageReadRecord(int xid, Page page, recordid rid, byte *buff) {
|
||||||
|
|
||||||
byte *recAddress = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
byte *recAddress = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
||||||
|
|
||||||
/*look at record, if slot offset == blob_slot, then its a blob, else its normal. */
|
|
||||||
/* if(isBlobSlot(page.memAddr, rid.slot)) {
|
|
||||||
int fd = -1;
|
|
||||||
int version;
|
|
||||||
int offset;
|
|
||||||
int length;
|
|
||||||
|
|
||||||
version = *(int *)recAddress;
|
|
||||||
offset = *(int *)(recAddress + 4);
|
|
||||||
length = *(int *)(recAddress + 8);
|
|
||||||
|
|
||||||
fd = version == 0 ? blobfd0 : blobfd1;
|
|
||||||
|
|
||||||
/ * if( (fd = open(version == 0 ? BLOB0_FILE : BLOB1_FILE, O_RDWR, 0)) == -1 ) {
|
|
||||||
printf("page.c:pageReadRecord error and exiting\n");
|
|
||||||
exit(-1);
|
|
||||||
} * /
|
|
||||||
lseek(fd, offset, SEEK_SET);
|
|
||||||
read(fd, buff, length);
|
|
||||||
/ * close(fd); * /
|
|
||||||
} else { */
|
|
||||||
/* For now, we need page.c to trust the rid. */
|
|
||||||
/* int size = getSecondHalfOfWord((int*)slotMemAddr(page.memAddr, rid.slot)); */
|
|
||||||
|
|
||||||
memcpy(buff, recAddress, rid.size);
|
memcpy(buff, recAddress, rid.size);
|
||||||
/*}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pageWriteRecord(int xid, Page page, recordid rid, const byte *data) {
|
void pageWriteRecord(int xid, Page page, recordid rid, const byte *data) {
|
||||||
|
|
||||||
byte *rec;
|
byte *rec;
|
||||||
/* int version = -1;
|
|
||||||
int fd = -1;
|
|
||||||
int blobRec[3];
|
|
||||||
|
|
||||||
if (isBlobSlot(page.memAddr, rid.slot)) {
|
|
||||||
/ * TODO: Rusty's wild guess as to what's supposed to happen. Touch blob appears to lookup the blob,
|
|
||||||
and allocate it if its not there. It returns 0 if it's a new blob, 1 otherwise, so I think we
|
|
||||||
just ignore its return value...* /
|
|
||||||
|
|
||||||
if( !touchBlob(xid, rid) ) {
|
|
||||||
/ * record hasn't been touched yet * /
|
|
||||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
|
||||||
version = *(int *)rec;
|
|
||||||
blobRec[0] = version == 0 ? 1 : 0;
|
|
||||||
blobRec[1] = *(int *)(rec + 4);
|
|
||||||
blobRec[2] = *(int *)(rec + 8);
|
|
||||||
memcpy(rec, blobRec, BLOB_REC_SIZE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = version == 0 ? blobfd0 : blobfd1;
|
|
||||||
|
|
||||||
if(-1 == lseek(fd, *(int *)(rec +4), SEEK_SET)) {
|
|
||||||
perror("lseek");
|
|
||||||
}
|
|
||||||
if(-1 == write(fd, data, *(int *)(rec +8))) {
|
|
||||||
perror("write");
|
|
||||||
}
|
|
||||||
|
|
||||||
/ * Flush kernel buffers to hard drive. TODO: the
|
|
||||||
(standard) fdatasync() call only flushes the data
|
|
||||||
instead of the data + metadata. Need to have
|
|
||||||
makefile figure out if it's available, and do some
|
|
||||||
macro magic in order to use it, if possible...
|
|
||||||
|
|
||||||
This is no longer called here, since it is called at commit.
|
|
||||||
* /
|
|
||||||
/ * fsync(fd); * /
|
|
||||||
} else { / * write a record that is not a blob */
|
|
||||||
|
|
||||||
assert(rid.size < PAGE_SIZE);
|
assert(rid.size < PAGE_SIZE);
|
||||||
|
|
||||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
||||||
|
|
||||||
if(memcpy(rec, data, rid.size) == NULL ) {
|
if(memcpy(rec, data, rid.size) == NULL ) {
|
||||||
printf("ERROR: MEM_WRITE_ERROR on %s line %d", __FILE__, __LINE__);
|
printf("ERROR: MEM_WRITE_ERROR on %s line %d", __FILE__, __LINE__);
|
||||||
exit(MEM_WRITE_ERROR);
|
exit(MEM_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
/*}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Currently not called any where, or tested. */
|
|
||||||
/*byte * pageMMapRecord(int xid, Page page, recordid rid) {
|
|
||||||
byte *rec;
|
|
||||||
int version = -1;
|
|
||||||
int fd = -1;
|
|
||||||
int blobRec[3];
|
|
||||||
byte * ret;
|
|
||||||
if (isBlobSlot(page.memAddr, rid.slot)) {
|
|
||||||
/ * TODO: Rusty's wild guess as to what's supposed to happen. Touch blob appears to lookup the blob,
|
|
||||||
and allocate it if its not there. It returns 0 if it's a new blob, 1 otherwise, so I think we
|
|
||||||
just ignore its return value...* /
|
|
||||||
|
|
||||||
if( !touchBlob(xid, rid) ) {
|
|
||||||
/ * record hasn't been touched yet * /
|
|
||||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
|
||||||
version = *(int *)rec;
|
|
||||||
blobRec[0] = version == 0 ? 1 : 0;
|
|
||||||
blobRec[1] = *(int *)(rec + 4);
|
|
||||||
blobRec[2] = *(int *)(rec + 8);
|
|
||||||
memcpy(rec, blobRec, BLOB_REC_SIZE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = version == 0 ? blobfd0 : blobfd1;
|
|
||||||
|
|
||||||
if((ret = mmap((byte*) 0, *(int *)(rec +8), (PROT_READ | PROT_WRITE), MAP_SHARED, fd, *(int *)(rec +4))) == (byte*)-1) {
|
|
||||||
perror("pageMMapRecord");
|
|
||||||
}
|
|
||||||
|
|
||||||
/ * if(-1 == lseek(fd, *(int *)(rec +4), SEEK_SET)) {
|
|
||||||
perror("lseek");
|
|
||||||
}
|
|
||||||
if(-1 == write(fd, data, *(int *)(rec +8))) {
|
|
||||||
perror("write");
|
|
||||||
} * /
|
|
||||||
|
|
||||||
/ * Flush kernel buffers to hard drive. TODO: the
|
|
||||||
(standard) fdatasync() call only flushes the data
|
|
||||||
instead of the data + metadata. Need to have
|
|
||||||
makefile figure out if it's available, and do some
|
|
||||||
macro magic in order to use it, if possible...* /
|
|
||||||
/ * fsync(fd); * /
|
|
||||||
|
|
||||||
} else { / * write a record that is not a blob * /
|
|
||||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
|
||||||
|
|
||||||
ret = rec;
|
|
||||||
/ * if(memcpy(rec, data, rid.size) == NULL ) {
|
|
||||||
printf("ERROR: MEM_WRITE_ERROR on %s line %d", __FILE__, __LINE__);
|
|
||||||
exit(MEM_WRITE_ERROR);
|
|
||||||
}* /
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void pageRealloc(Page *p, int id) {
|
void pageRealloc(Page *p, int id) {
|
||||||
p->id = id;
|
p->id = id;
|
||||||
p->LSN = 0;
|
p->LSN = 0;
|
||||||
|
@ -706,16 +490,16 @@ Page pool[MAX_BUFFER_SIZE];
|
||||||
Allocate a new page.
|
Allocate a new page.
|
||||||
@param id The id of the new page.
|
@param id The id of the new page.
|
||||||
@return A pointer to the new page. This memory is part of a pool,
|
@return A pointer to the new page. This memory is part of a pool,
|
||||||
and should not be freed by the application.
|
and should never be freed by manually.
|
||||||
*/
|
*/
|
||||||
Page *pageAlloc(int id) {
|
Page *pageAlloc(int id) {
|
||||||
Page *p = &(pool[nextPage]);
|
Page *p = &(pool[nextPage]);
|
||||||
|
|
||||||
nextPage++;
|
nextPage++;
|
||||||
|
|
||||||
assert(nextPage <= MAX_BUFFER_SIZE);
|
assert(nextPage <= MAX_BUFFER_SIZE);
|
||||||
/*
|
|
||||||
Page *p = (Page*)malloc(sizeof(Page));*/ /* freed in bufDeinit */
|
|
||||||
/* assert(p); */
|
|
||||||
pageRealloc(p, id);
|
pageRealloc(p, id);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,58 +561,6 @@ int pageTest() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
recordid pageBalloc(Page page, int size, int fileOffset) {
|
|
||||||
int freeSpace = readFreeSpace(page.memAddr);
|
|
||||||
int numSlots = readNumSlots(page.memAddr);
|
|
||||||
recordid rid;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
rid.page = page.id;
|
|
||||||
rid.slot = numSlots;
|
|
||||||
rid.size = size;
|
|
||||||
|
|
||||||
if (freespace(page) < BLOB_REC_SIZE) {
|
|
||||||
printf("Error in pageRalloc()\n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < numSlots; i++) {
|
|
||||||
if (!isValidSlot(page.memAddr, i)) {
|
|
||||||
rid.slot = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rid.slot == numSlots) {
|
|
||||||
writeNumSlots(page.memAddr, numSlots+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSlotOffset(page.memAddr, rid.slot, freeSpace);
|
|
||||||
setSlotLength(page.memAddr, rid.slot, BLOB_SLOT);
|
|
||||||
writeFreeSpace(page.memAddr, freeSpace + BLOB_REC_SIZE);
|
|
||||||
|
|
||||||
|
|
||||||
*(int *)(page.memAddr + freeSpace) = 0;
|
|
||||||
*(int *)(page.memAddr + freeSpace + 4) = fileOffset;
|
|
||||||
*(int *)(page.memAddr + freeSpace + 8) = size;
|
|
||||||
|
|
||||||
return rid;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
int getBlobOffset(int page, int slot) {
|
|
||||||
printf("Error: not yet implemented!!\n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getBlobSize(int page, int slot) {
|
|
||||||
printf("Error: not yet implemented!!\n");
|
|
||||||
exit(-1);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void setSlotType(Page p, int slot, int type) {
|
void setSlotType(Page p, int slot, int type) {
|
||||||
|
|
||||||
assert(type > PAGE_SIZE);
|
assert(type > PAGE_SIZE);
|
||||||
|
|
|
@ -1,460 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
|
|
||||||
/*****************
|
|
||||||
* @file
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* Implements recovery for a NO STEAL system -- we won't need any undo functions, CLRs, or to redo any aborted/uncommitted transactions
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @see recovery2.c
|
|
||||||
* *************/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "recovery.h"
|
|
||||||
#include <lladd/transactional.h>
|
|
||||||
#include <lladd/common.h>
|
|
||||||
#include "linkedlist.h"
|
|
||||||
#include <lladd/logger.h>
|
|
||||||
#include "logger/logparser.h"
|
|
||||||
#include "logger/logstreamer.h"
|
|
||||||
#include <pbl/pbl.h>
|
|
||||||
#include <lladd/page.h>
|
|
||||||
#include <lladd/bufferManager.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
/* just set an arbitrary recovery xid */
|
|
||||||
#define RECOVERY_XID 69
|
|
||||||
/* moved from recovery.h, sice this is the only file that uses it. */
|
|
||||||
|
|
||||||
static void undoUpdateRec(CommonLog cl, UpdateLog ul);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* map from page number to the recLSN that dirtied it */
|
|
||||||
static pblHashTable_t *dirtyPages;
|
|
||||||
/* sorted list of recLSNs of active transactiosn */
|
|
||||||
|
|
||||||
static LinkedListPtr transRecLSNs=NULL;
|
|
||||||
|
|
||||||
/* map from transID to status of the transaction: U (to be undone), or not in
|
|
||||||
* there, or committed but not ended (C)
|
|
||||||
* */
|
|
||||||
static pblHashTable_t *transTable;
|
|
||||||
|
|
||||||
/* the LSN of the dirty page with the smallest corresponding LSN */
|
|
||||||
static long minDirtyLSN;
|
|
||||||
|
|
||||||
|
|
||||||
void undoUpdateRec(CommonLog cl, UpdateLog ul) {
|
|
||||||
int undoIndex = operationsTable[ul.funcID].undo;
|
|
||||||
long CLRLSN;
|
|
||||||
CLRLSN = LogCLR(-1, cl.xid, cl.LSN, ul.rid, cl.prevLSN);
|
|
||||||
/*printf ("Undoing LSN=%ld (and writing new pageLSN=%ld\n", cl.LSN, CLRLSN); */
|
|
||||||
if (undoIndex==NO_INVERSE)
|
|
||||||
writeRecord(RECOVERY_XID, ul.rid, ul.preImage); /*if there's no inverse we directly write the preimage to the record*/
|
|
||||||
else operationsTable[undoIndex].run(RECOVERY_XID, ul.rid, ul.args);
|
|
||||||
writeLSN(CLRLSN, ul.rid.page);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Do this CLR action, and return the undoNextLSN listed in this clrlog
|
|
||||||
*/
|
|
||||||
/*static long DoCLRAction(CLRLog clrlog) {
|
|
||||||
UpdateLog ul;
|
|
||||||
CommonLog commonLog = readCommonLogFromLSN(clrlog.thisUpdateLSN);
|
|
||||||
if (commonLog.type!=UPDATELOG) {
|
|
||||||
printf ("Don't know how to undo a non-update log (LSN=%ld)! Aborting undo...\n", commonLog.LSN);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ul = updateStringToParts(commonLog.extraData);
|
|
||||||
undoUpdate(commonLog, ul);
|
|
||||||
return clrlog.undoNextLSN;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redo this clrlog, and it doesn't write out any CLR for the CLR. For now copy
|
|
||||||
* and pasted form undoUpdate, make it cleaner in the future.
|
|
||||||
*/
|
|
||||||
static void RedoCLRAction(CLRLog clrlog) {
|
|
||||||
int undoIndex;
|
|
||||||
UpdateLog ul;
|
|
||||||
CommonLog commonLog = readCommonLogFromLSN(clrlog.thisUpdateLSN);
|
|
||||||
if (commonLog.type!=UPDATELOG) {
|
|
||||||
printf ("Don't know how to undo a non-update log (LSN=%ld)! Aborting undo...\n", commonLog.LSN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ul = updateStringToParts(commonLog.extraData);
|
|
||||||
undoIndex = operationsTable[ul.funcID].undo;
|
|
||||||
printf ("ReUndoing LSN=%ld\n", commonLog.LSN);
|
|
||||||
if (undoIndex==NO_INVERSE)
|
|
||||||
writeRecord(RECOVERY_XID, ul.rid, ul.preImage); /*if there's no inverse we directly write the preimage to the record*/
|
|
||||||
else operationsTable[undoIndex].run(RECOVERY_XID, ul.rid, ul.args);
|
|
||||||
writeLSN(commonLog.LSN, clrlog.rid.page);
|
|
||||||
}
|
|
||||||
static void recovInit() {
|
|
||||||
/* startLogStream(); */ /* This is now called after Tinit() opens the log (to support Tprepare, and to fix the reused XID bug) */
|
|
||||||
dirtyPages = pblHtCreate();
|
|
||||||
transTable = pblHtCreate();
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
loadCheckPoint scans the log from the end to find the most recent checkpoint
|
|
||||||
loads the dirty page table from the checkpoint
|
|
||||||
set the lsn to start to be one after the end_checkpoint log **check this-i think it should be one after begin_checkpoint
|
|
||||||
if there are no checkpoints, LSN starts is 0
|
|
||||||
*/
|
|
||||||
static void loadCheckPoint (long *endCheckptLSN) {
|
|
||||||
/*for now just assume no checkpoints
|
|
||||||
therefore committedtrans table and DPT are empty
|
|
||||||
start recovery at LSN 0 */
|
|
||||||
*endCheckptLSN = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
At end of recovery, wrap up --
|
|
||||||
delete the committed transaction list
|
|
||||||
|
|
||||||
possibly in the future: delete the log file
|
|
||||||
*/
|
|
||||||
static void CleanUp() {
|
|
||||||
/* void *trans; */
|
|
||||||
destroyList(transRecLSNs);
|
|
||||||
transRecLSNs = 0;
|
|
||||||
/*any pages that were dirty should be flushed to disk and then the
|
|
||||||
corresponding transaction ended */
|
|
||||||
/*flushAllPages(); */
|
|
||||||
/*trans = pblHtFirst(transTable);
|
|
||||||
while (trans!=NULL) {
|
|
||||||
LogEnd(-1, *(int *)pblHtCurrentKey(transTable));
|
|
||||||
trans = pblHtNext(transTable);
|
|
||||||
}*/
|
|
||||||
pblHtDelete(dirtyPages);
|
|
||||||
pblHtDelete(transTable);
|
|
||||||
flushLog();
|
|
||||||
/* closeLogStream(); */
|
|
||||||
bufTransCommit(RECOVERY_XID); /*What is this? */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns true ifa page must be redone
|
|
||||||
loads the page into loadedPage if it needs to be redone
|
|
||||||
*/
|
|
||||||
static int MustBeRedone(long entryLSN, int page, Page *loadedPage) {
|
|
||||||
/* if this log entry's page is dirty */
|
|
||||||
long tmp;
|
|
||||||
long *recLSN = pblHtLookup(dirtyPages, &page, sizeof(int));
|
|
||||||
if (recLSN!=NULL) {
|
|
||||||
/*unmalloc this entry in the table, don't need it anymore */
|
|
||||||
tmp = *recLSN;
|
|
||||||
/* if the log entry's LSN is less than the recLSN of the dirty page */
|
|
||||||
if (entryLSN <= tmp) {
|
|
||||||
/*load page into memory, if the log's LSN is greater than (more recent) the LSN of that actual page (as it was on disk) */
|
|
||||||
*loadedPage = loadPage(page);
|
|
||||||
if (entryLSN > readLSN(page))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Given a page number and the log's LSN, analyze the page, aka
|
|
||||||
look it up in the dirty page table and add it if it's not there, and
|
|
||||||
have the table reflect the most recent LSN
|
|
||||||
|
|
||||||
also keeps track of the smallest dirty LSN
|
|
||||||
*/
|
|
||||||
static void analyzePage(int page, long curLSN) {
|
|
||||||
long *LSNCopy;
|
|
||||||
/*add page to the dirty page table if not there already with recLSN equal to this LSN */
|
|
||||||
long *oldLSN = pblHtLookup(dirtyPages, &page, sizeof(int));
|
|
||||||
if (oldLSN==NULL) {
|
|
||||||
/*make a new entry */
|
|
||||||
LSNCopy = (long *)malloc(sizeof(long));
|
|
||||||
*LSNCopy = curLSN;
|
|
||||||
pblHtInsert( dirtyPages, &page, sizeof(int), LSNCopy);
|
|
||||||
} else {
|
|
||||||
/*update the old entry to have the most recent LSN */
|
|
||||||
*oldLSN = curLSN;
|
|
||||||
}
|
|
||||||
/*if it's the smallest dirty LSN, make note of it */
|
|
||||||
if (minDirtyLSN==-1 || curLSN < minDirtyLSN)
|
|
||||||
minDirtyLSN = curLSN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analysis is the first phase:
|
|
||||||
* 1) determines the point in the log at which to start the Redo pass
|
|
||||||
* 2) determines (a conservative superset of the) pages in the buffer pool
|
|
||||||
* that were dirty at the time of the crash
|
|
||||||
*
|
|
||||||
* At the end of Analysis, transaction table contains accurate list of all
|
|
||||||
* transactions that were active at the time of the crash, and dirty page table
|
|
||||||
* includes all pages that were dirty ta time of crash (plus maybe some that
|
|
||||||
* were written to disk)
|
|
||||||
*/
|
|
||||||
static void RecovAnalysis () {
|
|
||||||
long curLSN, *thisTLSN;
|
|
||||||
int highestXid = -1;
|
|
||||||
CommonLog logEntry;
|
|
||||||
UpdateLog ul;
|
|
||||||
recordid thisRid;
|
|
||||||
CLRLog clrlog;
|
|
||||||
char *status;
|
|
||||||
pblHashTable_t *transMaxLSN = pblHtCreate();
|
|
||||||
minDirtyLSN = -1;
|
|
||||||
loadCheckPoint(&curLSN); /*sets DPT, AT and the current LSN to the last checkpoint if there is on */
|
|
||||||
/*scan through the log until the end*/
|
|
||||||
logEntry = readCommonLogFromLSN(curLSN);
|
|
||||||
while (logEntry.valid==1) {
|
|
||||||
if(highestXid < logEntry.xid) {
|
|
||||||
highestXid = logEntry.xid;
|
|
||||||
}
|
|
||||||
if ((status = (char *)pblHtLookup(transTable, &logEntry.xid, sizeof(int)))==NULL) {
|
|
||||||
status = malloc(sizeof(char));
|
|
||||||
*status = 'U'; /*default is to be undone */
|
|
||||||
pblHtInsert(transTable, &logEntry.xid, sizeof(int), status);
|
|
||||||
}
|
|
||||||
if ((thisTLSN = (long *)pblHtLookup(transMaxLSN, &logEntry.xid, sizeof(int))) != NULL) {
|
|
||||||
removeVal(&transRecLSNs, *thisTLSN); /*it's not the max anymore -- will add another val in later */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
thisTLSN = (long *)malloc(sizeof(long));
|
|
||||||
*thisTLSN = -1;
|
|
||||||
pblHtInsert(transMaxLSN, &logEntry.xid, sizeof(int), thisTLSN);
|
|
||||||
}
|
|
||||||
curLSN = logEntry.LSN;
|
|
||||||
switch(logEntry.type) {
|
|
||||||
case XCOMMIT:
|
|
||||||
*status = 'C';
|
|
||||||
break;
|
|
||||||
case XEND:
|
|
||||||
pblHtRemove(transTable, &logEntry.xid, sizeof(int)); /*not a transaction anymore, remove it from the transaction table */
|
|
||||||
pblHtRemove(transMaxLSN, &logEntry.xid, sizeof(int));
|
|
||||||
break;
|
|
||||||
case UPDATELOG:
|
|
||||||
/*determine what page it modified*/
|
|
||||||
ul = updateStringToParts(logEntry.extraData);
|
|
||||||
analyzePage(ul.rid.page, logEntry.LSN);
|
|
||||||
free(logEntry.extraData);
|
|
||||||
/*removeVal(&transRecLSNs, *thisTLSN);*/
|
|
||||||
addSortedVal(&transRecLSNs, logEntry.LSN);
|
|
||||||
*thisTLSN = logEntry.LSN;
|
|
||||||
break;
|
|
||||||
case XALLOC:
|
|
||||||
thisRid = allocStringToRID(logEntry.extraData);
|
|
||||||
analyzePage(thisRid.page, logEntry.LSN);
|
|
||||||
free(logEntry.extraData);
|
|
||||||
/*removeVal(&transRecLSNs, *thisTLSN); */
|
|
||||||
addSortedVal(&transRecLSNs, logEntry.LSN);
|
|
||||||
*thisTLSN = logEntry.LSN;
|
|
||||||
break;
|
|
||||||
case CLRLOG:
|
|
||||||
clrlog = CLRStringToParts(logEntry.extraData);
|
|
||||||
analyzePage(clrlog.rid.page, logEntry.LSN);
|
|
||||||
addSortedVal(&transRecLSNs, logEntry.LSN);
|
|
||||||
*thisTLSN = logEntry.LSN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*printList(transRecLSNs); */
|
|
||||||
logEntry = readNextCommonLog();
|
|
||||||
}
|
|
||||||
TsetXIDCount(highestXid);
|
|
||||||
pblHtDelete(transMaxLSN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redo applies updates of all committed transactions if they haven't been flushed to disk yet
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void RecovRedo () {
|
|
||||||
long curLSN = minDirtyLSN; /* start with smallest recLSN in dirty page table */
|
|
||||||
UpdateLog ul;
|
|
||||||
/* long *recLSN, */
|
|
||||||
long nextLSN;
|
|
||||||
Page loadedPage;
|
|
||||||
CLRLog clrlog;
|
|
||||||
recordid rec;
|
|
||||||
int i;
|
|
||||||
CommonLog logEntry;
|
|
||||||
/* starting from there, scan forward until end of log */
|
|
||||||
logEntry = readCommonLogFromLSN(curLSN);
|
|
||||||
while (logEntry.valid!=0) {
|
|
||||||
/*for each redoable log record, check whether logged action must be redone - redoable actions are update logs/alloc logs and must be a committed transaction*/
|
|
||||||
if (pblHtLookup(transTable, &logEntry.xid, sizeof(int))!=NULL) {
|
|
||||||
switch (logEntry.type) { /*only look at redoable log entries */
|
|
||||||
case UPDATELOG:
|
|
||||||
ul = updateStringToParts(logEntry.extraData);
|
|
||||||
|
|
||||||
if (MustBeRedone(logEntry.LSN, ul.rid.page, &loadedPage)==1) {
|
|
||||||
/*reapply logged action, AND set LSN on page to the LSN of the redone log record, flush to disk(?)
|
|
||||||
note that this is going around logging (which is done in transactional) so this will be unlogged*/
|
|
||||||
printf ("redoing op %d at LSN=%ld (>%ld), rid (page, slot, size)=%d,%d,%d. args (length %d)=", ul.funcID, logEntry.LSN, loadedPage.LSN, ul.rid.page, ul.rid.slot, ul.rid.size, ul.argSize);
|
|
||||||
for (i=0; i<ul.argSize; i++)
|
|
||||||
printf ("%c", *(char*)(ul.args+i));
|
|
||||||
printf ("\n");
|
|
||||||
operationsTable[ul.funcID].run(RECOVERY_XID, ul.rid, ul.args);
|
|
||||||
/*loadedPage.LSN = logEntry.LSN;*/
|
|
||||||
writeLSN(logEntry.LSN, ul.rid.page);
|
|
||||||
}
|
|
||||||
/** @todo KLUDGE: updateStringToParts mallocs ul.args, while assembleUpdateLog does not. Therefore, we remove the const qualifier from ul.args here,
|
|
||||||
and free it. Elsewhere, we do not have to do this. */
|
|
||||||
free((byte*)ul.args);
|
|
||||||
break;
|
|
||||||
case XALLOC:
|
|
||||||
rec = allocStringToRID(logEntry.extraData);
|
|
||||||
if (MustBeRedone(logEntry.LSN, rec.page, &loadedPage)==1) {
|
|
||||||
/*reallocate the record in the page just like how it was before*/
|
|
||||||
printf ("redoing record allocation at LSN=%ld: rid=%d,%d,%ld where pageid=%d.\n", logEntry.LSN, rec.page, rec.slot, (long int)rec.size, (int)loadedPage.id);
|
|
||||||
pageSlotRalloc(loadedPage, rec);
|
|
||||||
writeLSN(logEntry.LSN, rec.page);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case CLRLOG:
|
|
||||||
clrlog = CLRStringToParts(logEntry.extraData);
|
|
||||||
if (MustBeRedone(logEntry.LSN, clrlog.rid.page, &loadedPage)==1) {
|
|
||||||
printf("redoing CLR at LSN=%ld (>%ld), rid=%d,%d,%ld...", logEntry.LSN, loadedPage.LSN, clrlog.rid.page, clrlog.rid.slot, (long int)clrlog.rid.size);
|
|
||||||
nextLSN = streamPos();
|
|
||||||
RedoCLRAction(clrlog);
|
|
||||||
seekInLog(nextLSN);
|
|
||||||
writeLSN(logEntry.LSN, clrlog.rid.page);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} /* switch*/
|
|
||||||
} /* committed trans IF */
|
|
||||||
if (logEntry.extraData)
|
|
||||||
free(logEntry.extraData);
|
|
||||||
logEntry = readNextCommonLog();
|
|
||||||
} /* while */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looking at the set of lastLSN values for all 'loser' (non ending)
|
|
||||||
* transactions, pick the most recent LSN, undo it (if it is an update log) and
|
|
||||||
* add in prevLSN to the set of to be looked at LSNs, or add undoNextLSN if it
|
|
||||||
* is a CLR log
|
|
||||||
*/
|
|
||||||
static void RecovUndo(int recovering) {
|
|
||||||
long LSNToLookAt;
|
|
||||||
CommonLog comLog;
|
|
||||||
UpdateLog ul;
|
|
||||||
CLRLog clrlog;
|
|
||||||
recordid rec;
|
|
||||||
Page loadedPage;
|
|
||||||
while (transRecLSNs!=NULL) {
|
|
||||||
LSNToLookAt = popMaxVal(&transRecLSNs);
|
|
||||||
comLog = readCommonLogFromLSN(LSNToLookAt);
|
|
||||||
switch (comLog.type) {
|
|
||||||
case UPDATELOG:
|
|
||||||
ul = updateStringToParts(comLog.extraData);
|
|
||||||
undoUpdateRec(comLog, ul);
|
|
||||||
if ((ul.funcID != OPERATION_PREPARE) ||
|
|
||||||
(!recovering)) {
|
|
||||||
if (comLog.prevLSN>0) /*0 or -1 are invalid LSNs*/
|
|
||||||
addSortedVal(&transRecLSNs, comLog.prevLSN);
|
|
||||||
/*else LogEnd(-1, comLog.xid);*/
|
|
||||||
} else if (ul.funcID == OPERATION_PREPARE) {
|
|
||||||
/* TODO: Ugly! */
|
|
||||||
printf("Reviving XID: %d\n", comLog.xid);
|
|
||||||
Trevive(comLog.xid, LSNToLookAt);
|
|
||||||
} else {
|
|
||||||
printf("EEK!\n");
|
|
||||||
}
|
|
||||||
/*else LogEnd(-1, comLog.xid);*/
|
|
||||||
break;
|
|
||||||
case CLRLOG:
|
|
||||||
clrlog = CLRStringToParts(comLog.extraData);
|
|
||||||
if (clrlog.undoNextLSN>0)
|
|
||||||
addSortedVal(&transRecLSNs, clrlog.undoNextLSN);
|
|
||||||
/*else LogEnd(-1, comLog.xid);*/
|
|
||||||
break;
|
|
||||||
case XALLOC:
|
|
||||||
rec = allocStringToRID(comLog.extraData);
|
|
||||||
|
|
||||||
loadedPage = loadPage(rec.page);
|
|
||||||
printf ("NOT undoing record allocation at LSN=%ld: rid=%d,%d,%ld where pageid=%d.\n", comLog.LSN, rec.page, rec.slot, (long int)rec.size, loadedPage.id);
|
|
||||||
/* If page is already in memory (likely), then this just gets a pointer to it. */
|
|
||||||
/* The next line is correct, but commented because it causes trouble with LLADD hash. */
|
|
||||||
/* pageDeRalloc(loadedPage, rec); */
|
|
||||||
if (comLog.prevLSN>0) /*0 or -1 are invalid LSNs*/
|
|
||||||
addSortedVal(&transRecLSNs, comLog.prevLSN);
|
|
||||||
break;
|
|
||||||
default: printf ("Unknown log type to undo (TYPE=%d, XID= %d, LSN=%ld), skipping...\n", comLog.type, comLog.xid, comLog.LSN);
|
|
||||||
if (comLog.prevLSN>0)
|
|
||||||
addSortedVal(&transRecLSNs, comLog.prevLSN);
|
|
||||||
/*else LogEnd(-1, comLog.xid);*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* because this messes with transRecLSNs,
|
|
||||||
* should NOT be called by recovery. Call it from
|
|
||||||
* non-recovery code!
|
|
||||||
*/
|
|
||||||
void undoTrans(Transaction t) {
|
|
||||||
if (transRecLSNs) {
|
|
||||||
destroyList(transRecLSNs);
|
|
||||||
}
|
|
||||||
transRecLSNs = 0;
|
|
||||||
if(t.LSN > 0) {
|
|
||||||
addSortedVal(&transRecLSNs, t.LSN);
|
|
||||||
} else {
|
|
||||||
/* printf ("Nothing to undo for xid %d\n", t.xid); I think this is normal for the sequence Tbegin, Tread, Tabort -- Rusty */
|
|
||||||
}
|
|
||||||
RecovUndo(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitiateRecovery () {
|
|
||||||
recovInit();
|
|
||||||
printf ("Analysis\n");
|
|
||||||
RecovAnalysis();
|
|
||||||
printf ("Redo\n");
|
|
||||||
RecovRedo();
|
|
||||||
printf ("Undo\n");
|
|
||||||
RecovUndo(1);
|
|
||||||
CleanUp();
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@file
|
|
||||||
|
|
||||||
Used to implement recovery.
|
|
||||||
|
|
||||||
@deprecated
|
|
||||||
@see recovery2.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __RECOVERY_H__
|
|
||||||
#define __RECOVERY_H__
|
|
||||||
|
|
||||||
#include "logger/logparser.h"
|
|
||||||
#include <lladd/transactional.h>
|
|
||||||
/*
|
|
||||||
Initiate the recovery method!
|
|
||||||
When finished, pages on disk fully reflect all committed transactions in the log
|
|
||||||
*/
|
|
||||||
void InitiateRecovery ();
|
|
||||||
|
|
||||||
void undoTrans(Transaction t);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -21,19 +21,6 @@
|
||||||
/** @todo This include is an artifact of our lack of infrastructure to support log iterator guards. */
|
/** @todo This include is an artifact of our lack of infrastructure to support log iterator guards. */
|
||||||
#include <lladd/operations/prepare.h>
|
#include <lladd/operations/prepare.h>
|
||||||
|
|
||||||
/** Maps from xid (int) to status:
|
|
||||||
NULL - Haven't seen XID
|
|
||||||
U - XID is scheduled for UNDO
|
|
||||||
C - XID committed, but not ended. (End records are written once
|
|
||||||
the XID is flushed to disk. They are only written during the
|
|
||||||
recovery process, and shutdown since LLADD follows a no force
|
|
||||||
policy.) @todo Implement end records.
|
|
||||||
|
|
||||||
@todo We don't ever read values out of this hash table... could it
|
|
||||||
be replaced entirely with transactionLSN?
|
|
||||||
|
|
||||||
*/
|
|
||||||
/*static pblHashTable_t * transactionStatus; */
|
|
||||||
static pblHashTable_t * transactionLSN;
|
static pblHashTable_t * transactionLSN;
|
||||||
static LinkedListPtr rollbackLSNs = NULL;
|
static LinkedListPtr rollbackLSNs = NULL;
|
||||||
/**
|
/**
|
||||||
|
@ -116,9 +103,8 @@ static void Analysis () {
|
||||||
not overwrite this transaction's work with stale data.)
|
not overwrite this transaction's work with stale data.)
|
||||||
|
|
||||||
The redo phase checks for a transaction's presence in
|
The redo phase checks for a transaction's presence in
|
||||||
transactionLSN before redoing its actions. Therefore, if
|
transactionLSN before redoing its actions. Therefore, if we
|
||||||
we remove this transaction from the transactionStatus hash,
|
remove this transaction from the hash, it will not be redone.
|
||||||
it will not be redone.
|
|
||||||
*/
|
*/
|
||||||
pblHtRemove(transactionLSN, &(e->xid), sizeof(int));
|
pblHtRemove(transactionLSN, &(e->xid), sizeof(int));
|
||||||
break;
|
break;
|
||||||
|
@ -140,9 +126,6 @@ static void Analysis () {
|
||||||
/* Don't want this XID in the list of rolled back lsn's since
|
/* Don't want this XID in the list of rolled back lsn's since
|
||||||
this XACT will be rolled back during redo. */
|
this XACT will be rolled back during redo. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* case XALLOC: */ /* @todo Don't use XALLOC anymore, dont need it here. */
|
|
||||||
/* assert (0); */
|
|
||||||
default:
|
default:
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
|
@ -156,13 +139,13 @@ static void Redo() {
|
||||||
LogEntry * e;
|
LogEntry * e;
|
||||||
|
|
||||||
while((e = nextInLog(&lh))) {
|
while((e = nextInLog(&lh))) {
|
||||||
/* int garbage; */
|
|
||||||
/* Check to see if this log entry is part of a transaction that needs to be redone. */
|
/* Check to see if this log entry is part of a transaction that needs to be redone. */
|
||||||
if(pblHtLookup(transactionLSN, &(e->xid), sizeof(int)) != NULL) {
|
if(pblHtLookup(transactionLSN, &(e->xid), sizeof(int)) != NULL) {
|
||||||
/* Check to see if this log entry contains an action that needs to be redone. */
|
/* Check to see if this log entry contains an action that needs to be redone. */
|
||||||
if(e->type == UPDATELOG ||
|
if(e->type == UPDATELOG ||
|
||||||
e->type == CLRLOG) {
|
e->type == CLRLOG) {
|
||||||
/* redoOperation checks the page that contains e->rid, so we
|
/* redoUpdate checks the page that contains e->rid, so we
|
||||||
don't need to check to see if the page is newer than this
|
don't need to check to see if the page is newer than this
|
||||||
log entry. */
|
log entry. */
|
||||||
redoUpdate(e);
|
redoUpdate(e);
|
||||||
|
@ -213,36 +196,30 @@ static void Undo(int recovery) {
|
||||||
|
|
||||||
/* printf("1"); fflush(NULL); */
|
/* printf("1"); fflush(NULL); */
|
||||||
|
|
||||||
/* This check was incorrect. Since blobManager may lazily
|
|
||||||
update the pageManager, it is possible for this test to
|
|
||||||
fail. In that case, the undo is handled by blob manager
|
|
||||||
(it removes this page from it's dirty blob list), not
|
|
||||||
us. (Nope, it is now, again correct--fixed blobManager)*/
|
|
||||||
|
|
||||||
assert(e->LSN <= this_lsn);
|
assert(e->LSN <= this_lsn);
|
||||||
|
|
||||||
/* printf("1a"); fflush(NULL); */
|
/* printf("1a"); fflush(NULL); */
|
||||||
|
|
||||||
/* Need to log a clr here. */
|
/* Need to log a clr here. */
|
||||||
|
|
||||||
clr_lsn = LogCLR(e);
|
clr_lsn = LogCLR(e);
|
||||||
/* writeLSN(clr_lsn, e->contents.update.rid.page); */
|
|
||||||
|
|
||||||
/* Undo update is a no-op if the page does not reflect this
|
/* Undo update is a no-op if the page does not reflect this
|
||||||
update, but it will write the new clr_lsn. */
|
update, but it will write the new clr_lsn if necessary. */
|
||||||
|
|
||||||
undoUpdate(e, clr_lsn);
|
undoUpdate(e, clr_lsn);
|
||||||
|
|
||||||
/* printf("1b"); fflush(NULL); */
|
/* printf("1b"); fflush(NULL); */
|
||||||
break;
|
break;
|
||||||
case CLRLOG:
|
case CLRLOG:
|
||||||
/* Don't need to do anything special to handle CLR's.
|
/* Don't need to do anything special to handle CLR's.
|
||||||
Iterator will correctly jump to clr's previous undo record. */
|
Iterator will correctly jump to clr's previous undo record. */
|
||||||
|
|
||||||
/* printf("2"); fflush(NULL); */
|
/* printf("2"); fflush(NULL); */
|
||||||
break;
|
break;
|
||||||
/* case XALLOC: */
|
|
||||||
/* Don't use xalloc anymore. */
|
|
||||||
/*assert(0);*/
|
|
||||||
break;
|
|
||||||
case XABORT:
|
case XABORT:
|
||||||
/* Since XABORT is a no-op, we can safely ignore it. (XABORT records may be passed in by undoTrans.)*/
|
/* Since XABORT is a no-op, we can silentlt ignore it. (XABORT
|
||||||
|
records may be passed in by undoTrans.)*/
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unknown log type to undo (TYPE=%d, XID= %d, LSN=%ld), skipping...\n", e->type, e->xid, e->LSN);
|
printf ("Unknown log type to undo (TYPE=%d, XID= %d, LSN=%ld), skipping...\n", e->type, e->xid, e->LSN);
|
||||||
|
@ -264,6 +241,7 @@ void InitiateRecovery() {
|
||||||
DEBUG("Undo started\n");
|
DEBUG("Undo started\n");
|
||||||
Undo(1);
|
Undo(1);
|
||||||
DEBUG("Recovery complete.\n");
|
DEBUG("Recovery complete.\n");
|
||||||
|
|
||||||
/** @todo Should we manually empty the hash table? */
|
/** @todo Should we manually empty the hash table? */
|
||||||
pblHtDelete(transactionLSN);
|
pblHtDelete(transactionLSN);
|
||||||
|
|
||||||
|
@ -277,10 +255,10 @@ void undoTrans(TransactionLog transaction) {
|
||||||
}
|
}
|
||||||
rollbackLSNs = 0;
|
rollbackLSNs = 0;
|
||||||
if(transaction.prevLSN > 0) {
|
if(transaction.prevLSN > 0) {
|
||||||
/* printf("scheduling lsn %ld for undo.\n", transaction.prevLSN); */
|
DEBUG("scheduling lsn %ld for undo.\n", transaction.prevLSN);
|
||||||
addSortedVal(&rollbackLSNs, transaction.prevLSN);
|
addSortedVal(&rollbackLSNs, transaction.prevLSN);
|
||||||
} else {
|
} else {
|
||||||
/* Nothing to undo. (Happens for read-only xacts. */
|
/* Nothing to undo. (Happens for read-only xacts.) */
|
||||||
}
|
}
|
||||||
|
|
||||||
Undo(0);
|
Undo(0);
|
||||||
|
|
|
@ -1,182 +0,0 @@
|
||||||
/*---
|
|
||||||
This software is copyrighted by the Regents of the University of
|
|
||||||
California, and other parties. The following terms apply to all files
|
|
||||||
associated with the software unless explicitly disclaimed in
|
|
||||||
individual files.
|
|
||||||
|
|
||||||
The authors hereby grant permission to use, copy, modify, distribute,
|
|
||||||
and license this software and its documentation for any purpose,
|
|
||||||
provided that existing copyright notices are retained in all copies
|
|
||||||
and that this notice is included verbatim in any distributions. No
|
|
||||||
written agreement, license, or royalty fee is required for any of the
|
|
||||||
authorized uses. Modifications to this software may be copyrighted by
|
|
||||||
their authors and need not follow the licensing terms described here,
|
|
||||||
provided that the new terms are clearly indicated on the first page of
|
|
||||||
each file where they apply.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
||||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
||||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
||||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
|
||||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
|
||||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
|
||||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
||||||
|
|
||||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
|
||||||
U.S. government, the Government shall have only "Restricted Rights" in
|
|
||||||
the software and related documentation as defined in the Federal
|
|
||||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
|
||||||
acquiring the software on behalf of the Department of Defense, the
|
|
||||||
software shall be classified as "Commercial Computer Software" and the
|
|
||||||
Government shall have only "Restricted Rights" as defined in Clause
|
|
||||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
|
||||||
authors grant the U.S. Government and others acting in its behalf
|
|
||||||
permission to use and distribute the software in accordance with the
|
|
||||||
terms specified in this license.
|
|
||||||
---*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* implements main interface to tranactional pages
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @see transactional2.c
|
|
||||||
* ************************************************/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <lladd/transactional.h>
|
|
||||||
#include <lladd/constants.h>
|
|
||||||
#include <lladd/logger.h>
|
|
||||||
#include <lladd/bufferManager.h>
|
|
||||||
#include "recovery.h"
|
|
||||||
|
|
||||||
Transaction XactionTable[MAX_TRANSACTIONS];
|
|
||||||
int numActiveXactions = 0;
|
|
||||||
int xidCount = 0;
|
|
||||||
#define INVALID_XTABLE_XID -1
|
|
||||||
|
|
||||||
int Tinit() {
|
|
||||||
|
|
||||||
memset(XactionTable, INVALID_XTABLE_XID, sizeof(Transaction)*MAX_TRANSACTIONS);
|
|
||||||
operationsTable[OPERATION_SET] = getSet();
|
|
||||||
operationsTable[OPERATION_INCREMENT] = getIncrement();
|
|
||||||
operationsTable[OPERATION_DECREMENT] = getDecrement();
|
|
||||||
operationsTable[OPERATION_PREPARE] = getPrepare();
|
|
||||||
operationsTable[OPERATION_LHINSERT] = getLHInsert();
|
|
||||||
operationsTable[OPERATION_LHREMOVE] = getLHRemove();
|
|
||||||
|
|
||||||
|
|
||||||
pageInit();
|
|
||||||
bufInit();
|
|
||||||
logInit();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Tbegin() {
|
|
||||||
|
|
||||||
int i, index = 0;
|
|
||||||
|
|
||||||
if( numActiveXactions == MAX_TRANSACTIONS )
|
|
||||||
return EXCEED_MAX_TRANSACTIONS;
|
|
||||||
else
|
|
||||||
numActiveXactions++;
|
|
||||||
|
|
||||||
for( i = 0; i < MAX_TRANSACTIONS; i++ ) {
|
|
||||||
xidCount++;
|
|
||||||
if( XactionTable[xidCount%MAX_TRANSACTIONS].xid == INVALID_XTABLE_XID ) {
|
|
||||||
index = xidCount%MAX_TRANSACTIONS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert( i < MAX_TRANSACTIONS );
|
|
||||||
|
|
||||||
XactionTable[index].xid = xidCount;
|
|
||||||
XactionTable[index].LSN = LogTransBegin(XactionTable[index]);
|
|
||||||
|
|
||||||
return XactionTable[index].xid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tupdate(int xid, recordid rid, const void *dat, int op) {
|
|
||||||
assert(numActiveXactions <= MAX_TRANSACTIONS);
|
|
||||||
writeLSN(XactionTable[xid%MAX_TRANSACTIONS].LSN = LogUpdate(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid, rid, operationsTable[op], dat), rid.page);
|
|
||||||
operationsTable[op].run(xid, rid, dat);
|
|
||||||
}
|
|
||||||
|
|
||||||
recordid Talloc(int xid, size_t size) {
|
|
||||||
recordid ret;
|
|
||||||
|
|
||||||
ret = ralloc(xid, size);
|
|
||||||
|
|
||||||
writeLSN(XactionTable[xid%MAX_TRANSACTIONS].LSN = LogTransAlloc(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid, ret), ret.page);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
void Tread(int xid, recordid rid, void *dat) {
|
|
||||||
|
|
||||||
readRecord(xid, rid, dat);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Tcommit(int xid) {
|
|
||||||
|
|
||||||
LogTransCommit(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid);
|
|
||||||
bufTransCommit(xid); /* unlocks pages */
|
|
||||||
XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID;
|
|
||||||
numActiveXactions--;
|
|
||||||
assert( numActiveXactions >= 0 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Tabort(int xid) {
|
|
||||||
/* should call undoTrans after log trans abort. undoTrans will cause pages to contain CLR values corresponding to */
|
|
||||||
undoTrans(XactionTable[xid%MAX_TRANSACTIONS]);
|
|
||||||
LogTransAbort(XactionTable[xid%MAX_TRANSACTIONS].LSN, xid);
|
|
||||||
bufTransAbort(xid);
|
|
||||||
XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID;
|
|
||||||
numActiveXactions--;
|
|
||||||
assert( numActiveXactions >= 0 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Tdeinit() {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for( i = 0; i < MAX_TRANSACTIONS; i++ ) {
|
|
||||||
if( XactionTable[i].xid != INVALID_XTABLE_XID ) {
|
|
||||||
Tabort(XactionTable[i].xid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert( numActiveXactions == 0 );
|
|
||||||
|
|
||||||
bufDeinit();
|
|
||||||
logDeinit();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Trevive(int xid, long lsn) {
|
|
||||||
int index = xid % MAX_TRANSACTIONS;
|
|
||||||
if(XactionTable[index].xid != INVALID_XTABLE_XID) {
|
|
||||||
printf("Clashing Tprepare()'ed XID's encountered on recovery!!\n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
XactionTable[index].xid = xid;
|
|
||||||
XactionTable[index].LSN = lsn;
|
|
||||||
numActiveXactions++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TsetXIDCount(xid) {
|
|
||||||
xidCount = xid;
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include <lladd/constants.h>
|
#include <lladd/constants.h>
|
||||||
#include <lladd/logger/logger2.h>
|
#include <lladd/logger/logger2.h>
|
||||||
#include <lladd/bufferManager.h>
|
#include <lladd/bufferManager.h>
|
||||||
#include <lladd/recovery2.h>
|
#include <lladd/recovery.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ int Tinit() {
|
||||||
openLogWriter();
|
openLogWriter();
|
||||||
|
|
||||||
InitiateRecovery();
|
InitiateRecovery();
|
||||||
/* logInit(); */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -66,9 +65,8 @@ void Tupdate(int xid, recordid rid, const void *dat, int op) {
|
||||||
|
|
||||||
assert(XactionTable[xid % MAX_TRANSACTIONS].prevLSN == e->LSN);
|
assert(XactionTable[xid % MAX_TRANSACTIONS].prevLSN == e->LSN);
|
||||||
|
|
||||||
/* printf("e->LSN: %ld\n", e->LSN); */
|
DEBUG("Tupdate() e->LSN: %ld\n", e->LSN);
|
||||||
|
|
||||||
/* writeLSN(e->LSN, rid.page); <-- Handled by doUpdate now */
|
|
||||||
doUpdate(e);
|
doUpdate(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,13 +89,14 @@ int Tcommit(int xid) {
|
||||||
int Tabort(int xid) {
|
int Tabort(int xid) {
|
||||||
lsn_t lsn;
|
lsn_t lsn;
|
||||||
lsn = LogTransAbort(&XactionTable[xid%MAX_TRANSACTIONS]);
|
lsn = LogTransAbort(&XactionTable[xid%MAX_TRANSACTIONS]);
|
||||||
/* should call undoTrans after log trans abort. undoTrans will cause pages to contain CLR values corresponding to */
|
|
||||||
|
|
||||||
/* @todo is the order of the next two calls important? */
|
/* @todo is the order of the next two calls important? */
|
||||||
undoTrans(XactionTable[xid%MAX_TRANSACTIONS]);
|
undoTrans(XactionTable[xid%MAX_TRANSACTIONS]);
|
||||||
bufTransAbort(xid, lsn);
|
bufTransAbort(xid, lsn);
|
||||||
|
|
||||||
XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID;
|
XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID;
|
||||||
numActiveXactions--;
|
numActiveXactions--;
|
||||||
|
|
||||||
assert( numActiveXactions >= 0 );
|
assert( numActiveXactions >= 0 );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +112,6 @@ int Tdeinit() {
|
||||||
assert( numActiveXactions == 0 );
|
assert( numActiveXactions == 0 );
|
||||||
|
|
||||||
bufDeinit();
|
bufDeinit();
|
||||||
/* logDeinit(); */
|
|
||||||
closeLogWriter();
|
closeLogWriter();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue