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
|
||||
* 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
|
||||
*
|
||||
|
@ -61,11 +75,23 @@ terms specified in this license.
|
|||
#include <lladd/operations.h>
|
||||
|
||||
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)
|
||||
|
||||
Operation getPrepare();
|
||||
|
||||
/**
|
||||
Recovery's undo phase uses this logHandle iterator guard to implement Tprepare().
|
||||
*/
|
||||
int prepareGuard(LogEntry * e, void * state);
|
||||
void * getPrepareGuardState();
|
||||
#endif
|
||||
|
|
12
lladd/page.h
12
lladd/page.h
|
@ -83,17 +83,6 @@ typedef struct Page_s {
|
|||
int queue;
|
||||
} 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
|
||||
* functions dealing with pages.
|
||||
|
@ -143,7 +132,6 @@ Page* pageAlloc(int id);
|
|||
recordid pageSlotRalloc(Page page, recordid rid);
|
||||
|
||||
int pageTest();
|
||||
recordid pageBalloc(Page page, int size, int offset);
|
||||
|
||||
int getSlotType(Page p, int slot, int type);
|
||||
void setSlotType(Page p, int slot, int type);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
/* stdio */
|
||||
|
||||
#include <sys/types.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) {
|
||||
recordid blob_rec_rid = rid;
|
||||
blob_rec_rid.size = size;
|
||||
/* writeRecord(xid, lsn, 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() {
|
||||
int blobfd0, blobfd1;
|
||||
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... */
|
||||
|
||||
/* First in buffer manager. */
|
||||
/* recordid rid = ralloc(xid, lsn, 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);
|
||||
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. */
|
||||
/* @todo What should writeRawRecord do with the lsn? */
|
||||
|
||||
/* Tset() needs to know to 'do the right thing' here, since we've
|
||||
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));
|
||||
|
||||
rid.size = blob_rec.size;
|
||||
|
@ -220,12 +217,11 @@ static void tripleHashRemove(int xid, recordid rid) {
|
|||
}*/
|
||||
|
||||
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;
|
||||
/* int readcount; */
|
||||
FILE * fd;
|
||||
long offset;
|
||||
|
||||
|
@ -233,14 +229,6 @@ void readBlob(int xid, recordid rid, void * buf) {
|
|||
|
||||
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;
|
||||
|
||||
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
|
||||
checked to be sure that it increases monotonically. */
|
||||
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);
|
||||
|
||||
blob_record_t rec;
|
||||
long offset;
|
||||
FILE * fd;
|
||||
|
@ -274,7 +263,7 @@ void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
|||
|
||||
if(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");
|
||||
|
||||
|
||||
|
@ -288,12 +277,6 @@ void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
|||
/* Tset() raw record */
|
||||
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 */
|
||||
|
||||
|
@ -307,83 +290,41 @@ void writeBlob(int xid, lsn_t lsn, recordid rid, const void * buf) {
|
|||
/* 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) {
|
||||
abortBlobs(xid);
|
||||
}
|
||||
|
||||
/**
|
||||
Just clean up the dirty list for this xid. @todo Check return values.
|
||||
|
||||
(Functionally equivalent to the old rmTouch() function. Just
|
||||
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) {
|
||||
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;
|
||||
|
||||
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)) {
|
||||
lsn_t * rid_lsn;
|
||||
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)) {
|
||||
|
|
|
@ -38,21 +38,19 @@ BEGIN_C_DECLS
|
|||
|
||||
|
||||
/**
|
||||
If blob is resident, return a pointer to it. Otherwise, check if
|
||||
it's dirty (it could have been stolen), an retrieve it from the
|
||||
appropriate blob file.
|
||||
Read the blob from the recordid rid into 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);
|
||||
|
||||
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
|
||||
|
@ -70,6 +68,12 @@ typedef struct {
|
|||
unsigned fd : 1;
|
||||
} 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);
|
||||
void openBlobStore();
|
||||
void closeBlobStore();
|
||||
|
|
|
@ -68,8 +68,6 @@ static unsigned int bufferSize = 1; /* < MAX_BUFFER_SIZE */
|
|||
static Page *repHead, *repMiddle, *repTail; /* replacement policy */
|
||||
|
||||
static int stable = -1;
|
||||
/*int blobfd0 = -1;
|
||||
int blobfd1 = -1;*/
|
||||
|
||||
static void pageMap(Page *ret) {
|
||||
|
||||
|
@ -95,12 +93,8 @@ int bufInit() {
|
|||
|
||||
bufferSize = 1;
|
||||
stable = -1;
|
||||
/* blobfd0 = -1;
|
||||
blobfd1 = -1; */
|
||||
|
||||
|
||||
/* Create STORE_FILE, BLOB0_FILE, BLOB1_FILE if necessary,
|
||||
then open it read/write
|
||||
/* Create STORE_FILE, if necessary, then open it read/write
|
||||
|
||||
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?)
|
||||
|
@ -141,27 +135,6 @@ int bufInit() {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -219,8 +192,14 @@ static void qRemove(Page *ret) {
|
|||
assert(ret != repHead);
|
||||
}
|
||||
|
||||
/**
|
||||
LRU-2S from Markatos "On Caching Searching Engine Results"
|
||||
|
||||
@todo Should this be its own file?
|
||||
|
||||
*/
|
||||
static Page *kickPage(int pageid) {
|
||||
/* LRU-2S from Markatos "On Caching Searching Engine Results" */
|
||||
|
||||
Page *ret = repTail;
|
||||
|
||||
assert( bufferSize == MAX_BUFFER_SIZE );
|
||||
|
@ -328,38 +307,22 @@ Page loadPage (int pageid) {
|
|||
return *loadPagePtr(pageid);
|
||||
}
|
||||
|
||||
/*int lastGoodPageKey = 0; */
|
||||
|
||||
Page * lastRallocPage = 0;
|
||||
|
||||
recordid ralloc(int xid, lsn_t lsn, size_t size) {
|
||||
static unsigned int lastFreepage = 0;
|
||||
recordid ret;
|
||||
Page p;
|
||||
/* int blobSize = 0; */
|
||||
|
||||
if (size >= BLOB_THRESHOLD_SIZE) { /* TODO combine this with if below */
|
||||
|
||||
ret = allocBlob(xid, lsn, size);
|
||||
/* blobSize = size;
|
||||
size = BLOB_REC_SIZE; */
|
||||
|
||||
} else {
|
||||
|
||||
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);
|
||||
|
||||
/* } */
|
||||
}
|
||||
DEBUG("alloced rid = {%d, %d, %d}\n", ret.page, ret.slot, ret.size);
|
||||
return ret;
|
||||
|
@ -441,7 +404,6 @@ void bufDeinit() {
|
|||
printf("ERROR: flushPage on %s line %d", __FILE__, __LINE__);
|
||||
exit(ret);
|
||||
}
|
||||
/* free(p); */
|
||||
}
|
||||
pblHtDelete(activePages);
|
||||
|
||||
|
@ -450,8 +412,6 @@ void bufDeinit() {
|
|||
exit(errno);
|
||||
}
|
||||
|
||||
/* close(blobfd0);
|
||||
close(blobfd1); */
|
||||
closeBlobStore();
|
||||
|
||||
return;
|
||||
|
@ -462,12 +422,8 @@ void bufDeinit() {
|
|||
*/
|
||||
void simulateBufferManagerCrash() {
|
||||
closeBlobStore();
|
||||
/*close(blobfd0);
|
||||
close(blobfd1);*/
|
||||
|
||||
close(stable);
|
||||
/* blobfd0 = -1;
|
||||
blobfd1 = -1; */
|
||||
stable = -1;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,6 @@ const byte * getUpdateArgs(const LogEntry * ret) {
|
|||
const byte * getUpdatePreImage(const LogEntry * ret) {
|
||||
assert(ret->type == UPDATELOG);
|
||||
if(operationsTable[ret->contents.update.funcID].undo != NO_INVERSE) {
|
||||
/* if(ret->contents.update.invertible) { */
|
||||
return NULL;
|
||||
} else {
|
||||
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->type = UPDATELOG;
|
||||
ret->contents.update.funcID = funcID;
|
||||
/* ret->contents.update.invertible = invertible; */
|
||||
ret->contents.update.rid = rid;
|
||||
ret->contents.update.argSize = argSize;
|
||||
|
||||
|
|
|
@ -188,16 +188,3 @@ LogEntry * readLSNEntry(lsn_t LSN) {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
lsn_t LogCLR(/*TransactionLog * l,*/ LogEntry * undone) {
|
||||
lsn_t LogCLR(LogEntry * undone) {
|
||||
lsn_t ret;
|
||||
LogEntry * e = allocCLRLogEntry(-1, undone->xid, undone->LSN, undone->contents.update.rid, undone->prevLSN);
|
||||
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
|
||||
log is flushed, but after bufferManager returns a rid), then the
|
||||
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
|
||||
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);
|
||||
|
|
|
@ -47,7 +47,6 @@ terms specified in this license.
|
|||
**********************************************/
|
||||
|
||||
#include <lladd/operations/prepare.h>
|
||||
/*#include "../logger/logstreamer.h"*/
|
||||
#include <lladd/logger/logWriter.h>
|
||||
#include <malloc.h>
|
||||
|
||||
|
@ -57,37 +56,17 @@ static int operate(int xid, recordid rid, const void *dat) {
|
|||
syncLog();
|
||||
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 o = {
|
||||
OPERATION_PREPARE, /* id */
|
||||
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 */
|
||||
};
|
||||
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);
|
||||
|
||||
touchedBlob_t *touched;
|
||||
size_t touchedLen;
|
||||
|
||||
|
||||
/**
|
||||
* pageInit() initializes all the important variables needed in
|
||||
* all the functions dealing with pages.
|
||||
|
@ -173,90 +169,8 @@ void pageInit() {
|
|||
MASK_0000FFFF = (1 << (2*BITS_PER_BYTE)) - 1;
|
||||
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) {
|
||||
/* rmTouch(xid); */
|
||||
}
|
||||
|
@ -265,8 +179,6 @@ void pageAbort(int xid) {
|
|||
/* rmTouch(xid); */
|
||||
}
|
||||
|
||||
/*#define getFirstHalfOfWord(memAddr) (((*(int*)memAddr) >> (2*BITS_PER_BYTE)) & MASK_0000FFFF) */
|
||||
|
||||
static int getFirstHalfOfWord(unsigned int *memAddr) {
|
||||
unsigned int word = *memAddr;
|
||||
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
|
||||
* 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) {
|
||||
int freeSpace = readFreeSpace(page.memAddr);
|
||||
|
@ -393,12 +307,11 @@ recordid pageRalloc(Page page, size_t size) {
|
|||
rid.page = page.id;
|
||||
rid.slot = numSlots;
|
||||
rid.size = size;
|
||||
/*int i; */
|
||||
|
||||
/* 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++) {
|
||||
if (!isValidSlot(page.memAddr, i)) {
|
||||
rid.slot = i;
|
||||
|
@ -468,12 +381,12 @@ void pageCompact(Page page) {
|
|||
|
||||
int i;
|
||||
byte buffer[PAGE_SIZE];
|
||||
/* char *buffer = (char *)malloc(PAGE_SIZE); */
|
||||
int freeSpace = 0;
|
||||
int numSlots = readNumSlots(page.memAddr);
|
||||
int meta_size = LSN_SIZE + FREE_SPACE_SIZE + NUMSLOTS_SIZE + (SLOT_SIZE*numSlots);
|
||||
int slot_length;
|
||||
int last_used_slot = 0;
|
||||
|
||||
/* Can't compact in place, slot numbers can come in different orders than
|
||||
the physical space allocated to them. */
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
Blob format:
|
||||
|
||||
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:
|
||||
|
||||
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...
|
||||
|
||||
/*
|
||||
@todo This needs should trust the rid (since the caller needs to
|
||||
overrid the size in special circumstances, but if the size has been
|
||||
overridden, we should check for the circumstances where doing so is
|
||||
allowed.
|
||||
*/
|
||||
void pageReadRecord(int xid, Page page, recordid rid, byte *buff) {
|
||||
|
||||
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);
|
||||
/*}*/
|
||||
|
||||
}
|
||||
|
||||
void pageWriteRecord(int xid, Page page, recordid rid, const byte *data) {
|
||||
|
||||
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);
|
||||
|
||||
rec = page.memAddr + getSlotOffset(page.memAddr, rid.slot);
|
||||
|
||||
if(memcpy(rec, data, rid.size) == NULL ) {
|
||||
printf("ERROR: MEM_WRITE_ERROR on %s line %d", __FILE__, __LINE__);
|
||||
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) {
|
||||
p->id = id;
|
||||
p->LSN = 0;
|
||||
|
@ -706,16 +490,16 @@ Page pool[MAX_BUFFER_SIZE];
|
|||
Allocate a new page.
|
||||
@param id The id of the new page.
|
||||
@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 *p = &(pool[nextPage]);
|
||||
|
||||
nextPage++;
|
||||
|
||||
assert(nextPage <= MAX_BUFFER_SIZE);
|
||||
/*
|
||||
Page *p = (Page*)malloc(sizeof(Page));*/ /* freed in bufDeinit */
|
||||
/* assert(p); */
|
||||
pageRealloc(p, id);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -777,58 +561,6 @@ int pageTest() {
|
|||
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) {
|
||||
|
||||
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. */
|
||||
#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 LinkedListPtr rollbackLSNs = NULL;
|
||||
/**
|
||||
|
@ -116,9 +103,8 @@ static void Analysis () {
|
|||
not overwrite this transaction's work with stale data.)
|
||||
|
||||
The redo phase checks for a transaction's presence in
|
||||
transactionLSN before redoing its actions. Therefore, if
|
||||
we remove this transaction from the transactionStatus hash,
|
||||
it will not be redone.
|
||||
transactionLSN before redoing its actions. Therefore, if we
|
||||
remove this transaction from the hash, it will not be redone.
|
||||
*/
|
||||
pblHtRemove(transactionLSN, &(e->xid), sizeof(int));
|
||||
break;
|
||||
|
@ -140,9 +126,6 @@ static void Analysis () {
|
|||
/* Don't want this XID in the list of rolled back lsn's since
|
||||
this XACT will be rolled back during redo. */
|
||||
break;
|
||||
|
||||
/* case XALLOC: */ /* @todo Don't use XALLOC anymore, dont need it here. */
|
||||
/* assert (0); */
|
||||
default:
|
||||
assert (0);
|
||||
}
|
||||
|
@ -156,13 +139,13 @@ static void Redo() {
|
|||
LogEntry * e;
|
||||
|
||||
while((e = nextInLog(&lh))) {
|
||||
/* int garbage; */
|
||||
|
||||
/* 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) {
|
||||
/* Check to see if this log entry contains an action that needs to be redone. */
|
||||
if(e->type == UPDATELOG ||
|
||||
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
|
||||
log entry. */
|
||||
redoUpdate(e);
|
||||
|
@ -213,36 +196,30 @@ static void Undo(int recovery) {
|
|||
|
||||
/* 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);
|
||||
|
||||
/* printf("1a"); fflush(NULL); */
|
||||
|
||||
/* Need to log a clr here. */
|
||||
|
||||
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
|
||||
update, but it will write the new clr_lsn. */
|
||||
update, but it will write the new clr_lsn if necessary. */
|
||||
|
||||
undoUpdate(e, clr_lsn);
|
||||
|
||||
/* printf("1b"); fflush(NULL); */
|
||||
break;
|
||||
case CLRLOG:
|
||||
/* Don't need to do anything special to handle CLR's.
|
||||
Iterator will correctly jump to clr's previous undo record. */
|
||||
|
||||
/* printf("2"); fflush(NULL); */
|
||||
break;
|
||||
/* case XALLOC: */
|
||||
/* Don't use xalloc anymore. */
|
||||
/*assert(0);*/
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
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");
|
||||
Undo(1);
|
||||
DEBUG("Recovery complete.\n");
|
||||
|
||||
/** @todo Should we manually empty the hash table? */
|
||||
pblHtDelete(transactionLSN);
|
||||
|
||||
|
@ -277,10 +255,10 @@ void undoTrans(TransactionLog transaction) {
|
|||
}
|
||||
rollbackLSNs = 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);
|
||||
} else {
|
||||
/* Nothing to undo. (Happens for read-only xacts. */
|
||||
/* Nothing to undo. (Happens for read-only xacts.) */
|
||||
}
|
||||
|
||||
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/logger/logger2.h>
|
||||
#include <lladd/bufferManager.h>
|
||||
#include <lladd/recovery2.h>
|
||||
#include <lladd/recovery.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -29,7 +29,6 @@ int Tinit() {
|
|||
openLogWriter();
|
||||
|
||||
InitiateRecovery();
|
||||
/* logInit(); */
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
@ -91,13 +89,14 @@ int Tcommit(int xid) {
|
|||
int Tabort(int xid) {
|
||||
lsn_t lsn;
|
||||
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? */
|
||||
undoTrans(XactionTable[xid%MAX_TRANSACTIONS]);
|
||||
bufTransAbort(xid, lsn);
|
||||
|
||||
XactionTable[xid%MAX_TRANSACTIONS].xid = INVALID_XTABLE_XID;
|
||||
numActiveXactions--;
|
||||
|
||||
assert( numActiveXactions >= 0 );
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,7 +112,6 @@ int Tdeinit() {
|
|||
assert( numActiveXactions == 0 );
|
||||
|
||||
bufDeinit();
|
||||
/* logDeinit(); */
|
||||
closeLogWriter();
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue