fixes / cleanups of Tprepare()
This commit is contained in:
parent
fb4e91debe
commit
944c7e984f
12 changed files with 167 additions and 67 deletions
|
@ -57,7 +57,16 @@ LogEntry * allocCommonLogEntry(lsn_t prevLSN, int xid, unsigned int type) {
|
||||||
ret->type = type;
|
ret->type = type;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
LogEntry * allocPrepareLogEntry(lsn_t prevLSN, int xid, lsn_t recLSN) {
|
||||||
|
LogEntry * ret = calloc(1,sizeof(struct __raw_log_entry)+sizeof(lsn_t));
|
||||||
|
ret->LSN = -1;
|
||||||
|
ret->prevLSN = prevLSN;
|
||||||
|
ret->xid = xid;
|
||||||
|
ret->type = XPREPARE;
|
||||||
|
*(lsn_t*)(((struct __raw_log_entry*)ret)+1)=recLSN;
|
||||||
|
// assert(sizeofLogEntry(ret) == sizeof(struct __raw_log_entry)+sizeof(lsn_t));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
const byte * getUpdateArgs(const LogEntry * ret) {
|
const byte * getUpdateArgs(const LogEntry * ret) {
|
||||||
assert(ret->type == UPDATELOG ||
|
assert(ret->type == UPDATELOG ||
|
||||||
ret->type == CLRLOG);
|
ret->type == CLRLOG);
|
||||||
|
@ -84,6 +93,11 @@ const byte * getUpdatePreImage(const LogEntry * ret) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lsn_t getPrepareRecLSN(const LogEntry *e) {
|
||||||
|
lsn_t ret = *(lsn_t*)(((struct __raw_log_entry*)e)+1);
|
||||||
|
if(ret == -1) { ret = e->LSN; }
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
LogEntry * allocUpdateLogEntry(lsn_t prevLSN, int xid,
|
LogEntry * allocUpdateLogEntry(lsn_t prevLSN, int xid,
|
||||||
unsigned int funcID, recordid rid,
|
unsigned int funcID, recordid rid,
|
||||||
const byte * args, unsigned int argSize,
|
const byte * args, unsigned int argSize,
|
||||||
|
@ -159,6 +173,8 @@ long sizeofLogEntry(const LogEntry * log) {
|
||||||
}
|
}
|
||||||
case INTERNALLOG:
|
case INTERNALLOG:
|
||||||
return LoggerSizeOfInternalLogEntry(log);
|
return LoggerSizeOfInternalLogEntry(log);
|
||||||
|
case XPREPARE:
|
||||||
|
return sizeof(struct __raw_log_entry)+sizeof(lsn_t);
|
||||||
default:
|
default:
|
||||||
return sizeof(struct __raw_log_entry);
|
return sizeof(struct __raw_log_entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,7 +297,7 @@ int openLogWriter() {
|
||||||
@internal
|
@internal
|
||||||
|
|
||||||
Unfortunately, this function can't just seek to the end of the
|
Unfortunately, this function can't just seek to the end of the
|
||||||
log. If it did, and a prior instance of LLADD crashed (and wrote
|
log. If it did, and a prior instance of Stasis crashed (and wrote
|
||||||
a partial entry), then the log would be corrupted. Therefore, we
|
a partial entry), then the log would be corrupted. Therefore, we
|
||||||
need to be a little bit smarter, and track the next LSN value
|
need to be a little bit smarter, and track the next LSN value
|
||||||
manually. Calculating it the first time would require a scan over
|
manually. Calculating it the first time would require a scan over
|
||||||
|
@ -310,9 +310,6 @@ int openLogWriter() {
|
||||||
The first time writeLogEntry is called, we seek from the highest
|
The first time writeLogEntry is called, we seek from the highest
|
||||||
LSN encountered so far to the end of the log.
|
LSN encountered so far to the end of the log.
|
||||||
|
|
||||||
@todo writeLogEntry implicitly ignores all log entries with xid = -1.
|
|
||||||
This is probably the wrong thing to do...
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int writeLogEntryUnlocked(LogEntry * e) {
|
static int writeLogEntryUnlocked(LogEntry * e) {
|
||||||
|
@ -481,7 +478,6 @@ static LogEntry * readLogEntry() {
|
||||||
LogEntry * ret = 0;
|
LogEntry * ret = 0;
|
||||||
lsn_t size;
|
lsn_t size;
|
||||||
lsn_t entrySize;
|
lsn_t entrySize;
|
||||||
|
|
||||||
lsn_t bytesRead = read(roLogFD, &size, sizeof(lsn_t));
|
lsn_t bytesRead = read(roLogFD, &size, sizeof(lsn_t));
|
||||||
|
|
||||||
if(bytesRead != sizeof(lsn_t)) {
|
if(bytesRead != sizeof(lsn_t)) {
|
||||||
|
|
|
@ -229,23 +229,37 @@ static lsn_t LogTransCommon(TransactionLog * l, int type) {
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
static lsn_t LogTransCommonPrepare(TransactionLog * l) {
|
||||||
|
LogEntry * e = allocPrepareLogEntry(l->prevLSN, l->xid, l->recLSN);
|
||||||
|
lsn_t ret;
|
||||||
|
|
||||||
/**
|
DEBUG("Log prepare xid = %d prevlsn = %lld reclsn = %lld, %lld\n",e->xid,e->prevLSN,l->recLSN, getPrepareRecLSN(e));
|
||||||
@todo This should be usable by all calls that sync the log; not just commit.
|
LogWrite(e);
|
||||||
*/
|
|
||||||
static lsn_t groupCommit(TransactionLog * l) {
|
if(l->prevLSN == -1) { l->recLSN = e->LSN; }
|
||||||
|
l->prevLSN = e->LSN;
|
||||||
|
DEBUG("Log Common prepare XXX %d, LSN: %ld type: %ld (prevLSN %ld)\n", e->xid,
|
||||||
|
(long int)e->LSN, (long int)e->type, (long int)e->prevLSN);
|
||||||
|
|
||||||
|
ret = e->LSN;
|
||||||
|
|
||||||
|
FreeLogEntry(e);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void groupForce(lsn_t l) {
|
||||||
static pthread_mutex_t check_commit = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t check_commit = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static pthread_cond_t tooFewXacts = PTHREAD_COND_INITIALIZER;
|
static pthread_cond_t tooFewXacts = PTHREAD_COND_INITIALIZER;
|
||||||
|
|
||||||
lsn_t ret = LogTransCommon(l, XCOMMIT);
|
|
||||||
|
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
|
|
||||||
pthread_mutex_lock(&check_commit);
|
pthread_mutex_lock(&check_commit);
|
||||||
if(LogFlushedLSN() >= ret) {
|
if(LogFlushedLSN() >= l) {
|
||||||
pthread_mutex_unlock(&check_commit);
|
pthread_mutex_unlock(&check_commit);
|
||||||
return ret;
|
return;
|
||||||
}
|
}
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
timeout.tv_sec = now.tv_sec;
|
timeout.tv_sec = now.tv_sec;
|
||||||
|
@ -266,21 +280,32 @@ static lsn_t groupCommit(TransactionLog * l) {
|
||||||
printf("Warning: %s:%d: pthread_cond_timedwait was interrupted by a signal in groupCommit(). Acting as though it timed out.\n", __FILE__, __LINE__);
|
printf("Warning: %s:%d: pthread_cond_timedwait was interrupted by a signal in groupCommit(). Acting as though it timed out.\n", __FILE__, __LINE__);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(LogFlushedLSN() >= ret) {
|
if(LogFlushedLSN() >= l) {
|
||||||
pendingCommits--;
|
pendingCommits--;
|
||||||
pthread_mutex_unlock(&check_commit);
|
pthread_mutex_unlock(&check_commit);
|
||||||
return ret;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(LogFlushedLSN() < ret) {
|
if(LogFlushedLSN() < l) {
|
||||||
syncLog_LogWriter();
|
syncLog_LogWriter();
|
||||||
syncLogCount++;
|
syncLogCount++;
|
||||||
pthread_cond_broadcast(&tooFewXacts);
|
pthread_cond_broadcast(&tooFewXacts);
|
||||||
}
|
}
|
||||||
assert(LogFlushedLSN() >= ret);
|
assert(LogFlushedLSN() >= l);
|
||||||
pendingCommits--;
|
pendingCommits--;
|
||||||
pthread_mutex_unlock(&check_commit);
|
pthread_mutex_unlock(&check_commit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lsn_t groupCommit(TransactionLog * l) {
|
||||||
|
lsn_t ret = LogTransCommon(l, XCOMMIT);
|
||||||
|
groupForce(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static lsn_t groupPrepare(TransactionLog * l) {
|
||||||
|
lsn_t ret = LogTransCommonPrepare(l);
|
||||||
|
groupForce(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +316,9 @@ lsn_t LogTransCommit(TransactionLog * l) {
|
||||||
lsn_t LogTransAbort(TransactionLog * l) {
|
lsn_t LogTransAbort(TransactionLog * l) {
|
||||||
return LogTransCommon(l, XABORT);
|
return LogTransCommon(l, XABORT);
|
||||||
}
|
}
|
||||||
|
lsn_t LogTransPrepare(TransactionLog * l) {
|
||||||
|
return groupPrepare(l);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@todo Does the handling of operation types / argument sizes belong
|
@todo Does the handling of operation types / argument sizes belong
|
||||||
|
|
|
@ -51,7 +51,7 @@ terms specified in this license.
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
recordid prepare_bogus_rec = { 0, 0, 0};
|
recordid prepare_bogus_rec = { 0, 0, 0};
|
||||||
|
|
||||||
static int operate(int xid, Page * p, lsn_t lsn, recordid rid, const void *dat) {
|
static int operate(int xid, Page * p, lsn_t lsn, recordid rid, const void *dat) {
|
||||||
|
@ -75,6 +75,7 @@ typedef struct{
|
||||||
int continueIterating;
|
int continueIterating;
|
||||||
int prevLSN;
|
int prevLSN;
|
||||||
int xid;
|
int xid;
|
||||||
|
int aborted;
|
||||||
} PrepareGuardState;
|
} PrepareGuardState;
|
||||||
|
|
||||||
void * getPrepareGuardState() {
|
void * getPrepareGuardState() {
|
||||||
|
@ -82,6 +83,7 @@ void * getPrepareGuardState() {
|
||||||
s->continueIterating = 1;
|
s->continueIterating = 1;
|
||||||
s->prevLSN = -1;
|
s->prevLSN = -1;
|
||||||
s->xid = -1;
|
s->xid = -1;
|
||||||
|
s->aborted = 0;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +91,14 @@ void * getPrepareGuardState() {
|
||||||
int prepareGuard(const LogEntry * e, void * state) {
|
int prepareGuard(const LogEntry * e, void * state) {
|
||||||
PrepareGuardState * pgs = state;
|
PrepareGuardState * pgs = state;
|
||||||
int ret = pgs->continueIterating;
|
int ret = pgs->continueIterating;
|
||||||
if(e->type == UPDATELOG) {
|
if(e->type == UPDATELOG && !pgs->aborted) {
|
||||||
if(e->update.funcID == OPERATION_PREPARE) {
|
if(e->update.funcID == OPERATION_PREPARE) {
|
||||||
pgs->continueIterating = 0;
|
pgs->continueIterating = 0;
|
||||||
pgs->prevLSN = e->prevLSN;
|
pgs->prevLSN = e->prevLSN;
|
||||||
}
|
}
|
||||||
|
} else if (e->type == XABORT) {
|
||||||
|
printf("xid %d aborted.\n", e->xid);
|
||||||
|
pgs->aborted = 1;
|
||||||
}
|
}
|
||||||
if(pgs->xid == -1) {
|
if(pgs->xid == -1) {
|
||||||
pgs->xid = e->xid;
|
pgs->xid = e->xid;
|
||||||
|
@ -109,9 +114,10 @@ int prepareGuard(const LogEntry * e, void * state) {
|
||||||
int prepareAction(void * state) {
|
int prepareAction(void * state) {
|
||||||
PrepareGuardState * pgs = state;
|
PrepareGuardState * pgs = state;
|
||||||
int ret;
|
int ret;
|
||||||
if(!pgs->continueIterating) {
|
if(!(pgs->continueIterating || pgs->aborted)) {
|
||||||
assert(pgs->prevLSN != -1);
|
//assert(pgs->prevLSN != -1);
|
||||||
Trevive(pgs->xid, pgs->prevLSN);
|
abort();
|
||||||
|
// Trevive(pgs->xid, pgs->prevLSN);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include <stasis/lockManager.h>
|
#include <stasis/lockManager.h>
|
||||||
|
|
||||||
/** @todo Add better log iterator guard support and remove this include.*/
|
/** @todo Add better log iterator guard support and remove this include.*/
|
||||||
#include <stasis/operations/prepare.h>
|
//#include <stasis/operations/prepare.h>
|
||||||
|
|
||||||
#include <stasis/logger/logHandle.h>
|
#include <stasis/logger/logHandle.h>
|
||||||
/** @todo Get rid of linkedlist */
|
/** @todo Get rid of linkedlist */
|
||||||
|
@ -60,13 +60,9 @@ static void Analysis () {
|
||||||
log was so that we don't accidentally reuse XID's. This keeps
|
log was so that we don't accidentally reuse XID's. This keeps
|
||||||
track of that value. */
|
track of that value. */
|
||||||
int highestXid = 0;
|
int highestXid = 0;
|
||||||
|
|
||||||
/** @todo loadCheckPoint() - Jump forward in the log to the last
|
|
||||||
checkpoint. (getLogHandle should do this automatically,
|
|
||||||
since the log will be truncated on checkpoint anyway.) */
|
|
||||||
|
|
||||||
while((e = nextInLog(&lh))) {
|
while((e = nextInLog(&lh))) {
|
||||||
|
|
||||||
lsn_t * xactLSN = (lsn_t*)pblHtLookup(transactionLSN, &(e->xid), sizeof(int));
|
lsn_t * xactLSN = (lsn_t*)pblHtLookup(transactionLSN, &(e->xid), sizeof(int));
|
||||||
|
|
||||||
if(highestXid < e->xid) {
|
if(highestXid < e->xid) {
|
||||||
|
@ -140,6 +136,9 @@ static void Analysis () {
|
||||||
DEBUG("Adding %ld\n", e->LSN);
|
DEBUG("Adding %ld\n", e->LSN);
|
||||||
addSortedVal(&rollbackLSNs, e->LSN);
|
addSortedVal(&rollbackLSNs, e->LSN);
|
||||||
break;
|
break;
|
||||||
|
case XPREPARE:
|
||||||
|
addSortedVal(&rollbackLSNs, e->LSN);
|
||||||
|
break; // XXX check to see if the xact exists?
|
||||||
case INTERNALLOG:
|
case INTERNALLOG:
|
||||||
// Created by the logger, just ignore it
|
// Created by the logger, just ignore it
|
||||||
// Make sure the log entry doesn't interfere with real xacts.
|
// Make sure the log entry doesn't interfere with real xacts.
|
||||||
|
@ -186,35 +185,34 @@ static void Redo() {
|
||||||
{
|
{
|
||||||
FreeLogEntry(e);
|
FreeLogEntry(e);
|
||||||
} break;
|
} break;
|
||||||
|
case XPREPARE:
|
||||||
|
{
|
||||||
|
FreeLogEntry(e);
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
@todo Guards shouldn't be hardcoded in Undo()
|
|
||||||
*/
|
|
||||||
static void Undo(int recovery) {
|
static void Undo(int recovery) {
|
||||||
LogHandle lh;
|
LogHandle lh;
|
||||||
void * prepare_guard_state;
|
|
||||||
|
|
||||||
while(rollbackLSNs != NULL) {
|
while(rollbackLSNs != NULL) {
|
||||||
const LogEntry * e;
|
const LogEntry * e;
|
||||||
lsn_t rollback = popMaxVal(&rollbackLSNs);
|
lsn_t rollback = popMaxVal(&rollbackLSNs);
|
||||||
|
|
||||||
prepare_guard_state = getPrepareGuardState();
|
|
||||||
|
|
||||||
DEBUG("Undoing LSN %ld\n", (long int)rollback);
|
DEBUG("Undoing LSN %ld\n", (long int)rollback);
|
||||||
|
|
||||||
if(recovery) {
|
lh = getLSNHandle(rollback);
|
||||||
lh = getGuardedHandle(rollback, &prepareGuard, prepare_guard_state);
|
|
||||||
} else {
|
|
||||||
lh = getLSNHandle(rollback);
|
|
||||||
}
|
|
||||||
|
|
||||||
int thisXid = -1;
|
int thisXid = -1;
|
||||||
while((e = previousInTransaction(&lh))) {
|
|
||||||
|
// Is this transaction just a loser, or was it aborted?
|
||||||
|
int reallyAborted = 0;
|
||||||
|
// Have we reached a XPREPARE that we should pay attention to?
|
||||||
|
int prepared = 0;
|
||||||
|
while((!prepared) && (e = previousInTransaction(&lh))) {
|
||||||
thisXid = e->xid;
|
thisXid = e->xid;
|
||||||
lsn_t this_lsn, clr_lsn;
|
lsn_t this_lsn, clr_lsn;
|
||||||
switch(e->type) {
|
switch(e->type) {
|
||||||
|
@ -229,9 +227,9 @@ static void Undo(int recovery) {
|
||||||
|
|
||||||
// If this fails, something is wrong with redo or normal operation.
|
// If this fails, something is wrong with redo or normal operation.
|
||||||
this_lsn = stasis_page_lsn_read(p);
|
this_lsn = stasis_page_lsn_read(p);
|
||||||
assert(e->LSN <= this_lsn);
|
assert(e->LSN <= this_lsn);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// The log entry is not associated with a particular page.
|
// The log entry is not associated with a particular page.
|
||||||
// (Therefore, it must be an idempotent logical log entry.)
|
// (Therefore, it must be an idempotent logical log entry.)
|
||||||
}
|
}
|
||||||
|
@ -249,12 +247,25 @@ static void Undo(int recovery) {
|
||||||
// Don't undo CLRs; they were undone during Redo
|
// Don't undo CLRs; they were undone during Redo
|
||||||
break;
|
break;
|
||||||
case XABORT:
|
case XABORT:
|
||||||
// Since XABORT is a no-op, we can silentlt ignore it. XABORT
|
printf("Found abort for %d\n", e->xid);
|
||||||
|
reallyAborted = 1;
|
||||||
|
// Since XABORT is a no-op, we can silently ignore it. XABORT
|
||||||
// records may be passed in by undoTrans.
|
// records may be passed in by undoTrans.
|
||||||
break;
|
break;
|
||||||
case XCOMMIT:
|
case XCOMMIT:
|
||||||
// Should never abort a transaction that contains a commit record
|
// Should never abort a transaction that contains a commit record
|
||||||
abort();
|
abort();
|
||||||
|
case XPREPARE: {
|
||||||
|
printf("found prepared xact %d\n", e->xid);
|
||||||
|
|
||||||
|
if(!reallyAborted) {
|
||||||
|
printf("xact wasn't aborted\n");
|
||||||
|
prepared = 1;
|
||||||
|
Trevive(e->xid, e->LSN, getPrepareRecLSN(e));
|
||||||
|
} else {
|
||||||
|
printf("xact was aborted\n");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
printf
|
printf
|
||||||
("Unknown log type to undo (TYPE=%d,XID= %d,LSN=%lld), skipping...\n",
|
("Unknown log type to undo (TYPE=%d,XID= %d,LSN=%lld), skipping...\n",
|
||||||
|
@ -264,9 +275,7 @@ static void Undo(int recovery) {
|
||||||
}
|
}
|
||||||
FreeLogEntry(e);
|
FreeLogEntry(e);
|
||||||
}
|
}
|
||||||
int transactionWasPrepared = prepareAction(prepare_guard_state);
|
if((!prepared) && globalLockManager.abort) {
|
||||||
free(prepare_guard_state);
|
|
||||||
if(!transactionWasPrepared && globalLockManager.abort) {
|
|
||||||
globalLockManager.abort(thisXid);
|
globalLockManager.abort(thisXid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ void setupOperationsTable() {
|
||||||
operationsTable[OPERATION_INCREMENT] = getIncrement();
|
operationsTable[OPERATION_INCREMENT] = getIncrement();
|
||||||
operationsTable[OPERATION_DECREMENT] = getDecrement();
|
operationsTable[OPERATION_DECREMENT] = getDecrement();
|
||||||
operationsTable[OPERATION_ALLOC] = getAlloc();
|
operationsTable[OPERATION_ALLOC] = getAlloc();
|
||||||
operationsTable[OPERATION_PREPARE] = getPrepare();
|
// operationsTable[OPERATION_PREPARE] = getPrepare();
|
||||||
/* operationsTable[OPERATION_LHINSERT] = getLHInsert();
|
/* operationsTable[OPERATION_LHINSERT] = getLHInsert();
|
||||||
operationsTable[OPERATION_LHREMOVE] = getLHRemove(); */
|
operationsTable[OPERATION_LHREMOVE] = getLHRemove(); */
|
||||||
operationsTable[OPERATION_DEALLOC] = getDealloc();
|
operationsTable[OPERATION_DEALLOC] = getDealloc();
|
||||||
|
@ -350,6 +350,14 @@ int Tcommit(int xid) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Tprepare(int xid) {
|
||||||
|
assert(xid >= 0);
|
||||||
|
off_t i = xid % MAX_TRANSACTIONS;
|
||||||
|
assert(XactionTable[i].xid == xid);
|
||||||
|
LogTransPrepare(&XactionTable[i]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Tabort(int xid) {
|
int Tabort(int xid) {
|
||||||
lsn_t lsn;
|
lsn_t lsn;
|
||||||
assert(xid >= 0);
|
assert(xid >= 0);
|
||||||
|
@ -427,24 +435,26 @@ int TuncleanShutdown() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trevive(int xid, long lsn) {
|
void Trevive(int xid, lsn_t prevlsn, lsn_t reclsn) {
|
||||||
assert(xid >= 0);
|
assert(xid >= 0);
|
||||||
|
assert(reclsn != -1);
|
||||||
int index = xid % MAX_TRANSACTIONS;
|
int index = xid % MAX_TRANSACTIONS;
|
||||||
pthread_mutex_lock(&transactional_2_mutex);
|
pthread_mutex_lock(&transactional_2_mutex);
|
||||||
|
|
||||||
DEBUG("Reviving xid %d at lsn %ld\n", xid, lsn);
|
DEBUG("Reviving xid %d at lsn %ld\n", xid, lsn);
|
||||||
|
|
||||||
if(XactionTable[index].xid != INVALID_XTABLE_XID) {
|
if(XactionTable[index].xid != INVALID_XTABLE_XID) {
|
||||||
if(xid != XactionTable[index].xid) {
|
abort();
|
||||||
|
/* if(xid != XactionTable[index].xid) {
|
||||||
fprintf(stderr, "Clashing Tprepare()'ed XID's encountered on recovery!!\n");
|
fprintf(stderr, "Clashing Tprepare()'ed XID's encountered on recovery!!\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
assert(XactionTable[index].xid == xid);
|
assert(XactionTable[index].xid == xid);
|
||||||
assert(XactionTable[index].prevLSN == lsn);
|
assert(XactionTable[index].prevLSN == lsn); */
|
||||||
} else {
|
} else {
|
||||||
XactionTable[index].xid = xid;
|
XactionTable[index].xid = xid;
|
||||||
XactionTable[index].prevLSN = lsn;
|
XactionTable[index].prevLSN = prevlsn;
|
||||||
|
XactionTable[index].recLSN = reclsn;
|
||||||
numActiveXactions++;
|
numActiveXactions++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -472,6 +482,22 @@ lsn_t transactions_minRecLSN() {
|
||||||
return minRecLSN;
|
return minRecLSN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int* TlistActiveTransactions() {
|
||||||
|
pthread_mutex_lock(&transactional_2_mutex);
|
||||||
|
int * ret = malloc(sizeof(*ret));
|
||||||
|
ret[0] = 0;
|
||||||
|
int retcount = 0;
|
||||||
|
for(int i = 0; i < MAX_TRANSACTIONS; i++) {
|
||||||
|
if(XactionTable[i].xid != INVALID_XTABLE_XID) {
|
||||||
|
ret[retcount] = XactionTable[i].xid;
|
||||||
|
retcount++;
|
||||||
|
ret = realloc(ret, (retcount+1) * sizeof(*ret));
|
||||||
|
ret[retcount] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&transactional_2_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
int TisActiveTransaction(int xid) {
|
int TisActiveTransaction(int xid) {
|
||||||
if(xid < 0) { return 0; }
|
if(xid < 0) { return 0; }
|
||||||
pthread_mutex_lock(&transactional_2_mutex);
|
pthread_mutex_lock(&transactional_2_mutex);
|
||||||
|
|
|
@ -215,14 +215,15 @@ extern const short SLOT_TYPE_LENGTHS[];
|
||||||
/**
|
/**
|
||||||
XEND is used for after the pages touched by a transaction have
|
XEND is used for after the pages touched by a transaction have
|
||||||
been flushed to stable storage.
|
been flushed to stable storage.
|
||||||
|
|
||||||
@todo Actually write XEND entries to the log so that log
|
|
||||||
truncation can be implemented!
|
|
||||||
|
|
||||||
|
@todo Actually write XEND entries to the log so that we can
|
||||||
|
use analysis to optimize redo.
|
||||||
*/
|
*/
|
||||||
#define XEND 6
|
#define XEND 6
|
||||||
#define CLRLOG 7
|
#define CLRLOG 7
|
||||||
|
|
||||||
|
#define XPREPARE 8
|
||||||
|
|
||||||
/* Page types */
|
/* Page types */
|
||||||
|
|
||||||
#define UNINITIALIZED_PAGE 0
|
#define UNINITIALIZED_PAGE 0
|
||||||
|
|
|
@ -90,6 +90,8 @@ typedef struct {
|
||||||
@return a LogEntry that should be freed with free().
|
@return a LogEntry that should be freed with free().
|
||||||
*/
|
*/
|
||||||
LogEntry * allocCommonLogEntry(lsn_t prevLSN, int xid, unsigned int type);
|
LogEntry * allocCommonLogEntry(lsn_t prevLSN, int xid, unsigned int type);
|
||||||
|
|
||||||
|
LogEntry * allocPrepareLogEntry(lsn_t prevLSN, int xid, lsn_t recLSN);
|
||||||
/**
|
/**
|
||||||
Allocate a log entry associated with an operation implemention. This
|
Allocate a log entry associated with an operation implemention. This
|
||||||
is usually called inside of Tupdate().
|
is usually called inside of Tupdate().
|
||||||
|
@ -124,6 +126,8 @@ const byte * getUpdateArgs(const LogEntry * e);
|
||||||
*/
|
*/
|
||||||
const byte * getUpdatePreImage(const LogEntry * e);
|
const byte * getUpdatePreImage(const LogEntry * e);
|
||||||
|
|
||||||
|
lsn_t getPrepareRecLSN(const LogEntry *e);
|
||||||
|
|
||||||
END_C_DECLS
|
END_C_DECLS
|
||||||
|
|
||||||
#endif /* __LOGENTRY_H */
|
#endif /* __LOGENTRY_H */
|
||||||
|
|
|
@ -130,18 +130,25 @@ lsn_t LogNextEntry(const LogEntry * e);
|
||||||
*/
|
*/
|
||||||
TransactionLog LogTransBegin(int xid);
|
TransactionLog LogTransBegin(int xid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Write a transaction PREPARE to the log tail. Blocks until the
|
||||||
|
prepare record is stable.
|
||||||
|
|
||||||
|
@return the lsn of the prepare log entry
|
||||||
|
*/
|
||||||
|
lsn_t LogTransPrepare(TransactionLog * l);
|
||||||
/**
|
/**
|
||||||
Write a transaction COMMIT to the log tail. Blocks until the commit
|
Write a transaction COMMIT to the log tail. Blocks until the commit
|
||||||
record is stable.
|
record is stable.
|
||||||
|
|
||||||
@return The lsn of the commit log entry.
|
@return the lsn of the commit log entry.
|
||||||
*/
|
*/
|
||||||
lsn_t LogTransCommit(TransactionLog * l);
|
lsn_t LogTransCommit(TransactionLog * l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Write a transaction ABORT to the log tail.
|
Write a transaction ABORT to the log tail. Does not force the log.
|
||||||
|
|
||||||
@return The lsn of the abort log entry.
|
@return the lsn of the abort log entry.
|
||||||
*/
|
*/
|
||||||
lsn_t LogTransAbort(TransactionLog * l);
|
lsn_t LogTransAbort(TransactionLog * l);
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ extern recordid prepare_bogus_rec;
|
||||||
@param rec must be a valid record id. any valid recordid will do. This parameter will be removed eventually.
|
@param rec must be a valid record id. any valid recordid will do. This parameter will be removed eventually.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#define Tprepare(xid, rec) Tupdate(xid, rec, 0, OPERATION_PREPARE)
|
//#define Tprepare(xid) Tupdate(xid, NULLRID, 0, OPERATION_PREPARE)
|
||||||
|
|
||||||
Operation getPrepare();
|
Operation getPrepare();
|
||||||
|
|
||||||
|
|
|
@ -591,7 +591,7 @@ extern const recordid NULLRID;
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int xid;
|
int xid;
|
||||||
long LSN;
|
lsn_t LSN;
|
||||||
} Transaction;
|
} Transaction;
|
||||||
|
|
||||||
|
|
||||||
|
@ -679,10 +679,11 @@ int TuncleanShutdown();
|
||||||
* Revives Tprepare'ed transactions.
|
* Revives Tprepare'ed transactions.
|
||||||
*
|
*
|
||||||
* @param xid The xid that is to be revived.
|
* @param xid The xid that is to be revived.
|
||||||
* @param lsn The lsn of that xid's most recent PREPARE entry in the log.
|
* @param prevlsn The lsn of that xid's most recent PREPARE entry in the log.
|
||||||
|
* @param reclsn The lsn of the transaction's BEGIN record.
|
||||||
*/
|
*/
|
||||||
void Trevive(int xid, long lsn);
|
void Trevive(int xid, lsn_t prevlsn, lsn_t reclsn);
|
||||||
|
int Tprepare(int xid);
|
||||||
/**
|
/**
|
||||||
* Used by the recovery process.
|
* Used by the recovery process.
|
||||||
*
|
*
|
||||||
|
@ -693,6 +694,13 @@ void Trevive(int xid, long lsn);
|
||||||
*/
|
*/
|
||||||
void TsetXIDCount(int xid);
|
void TsetXIDCount(int xid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
List all active transactions.
|
||||||
|
|
||||||
|
@return an array of transaction ids.
|
||||||
|
*/
|
||||||
|
int* TlistActiveTransactions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if a transaction is still active.
|
* Checks to see if a transaction is still active.
|
||||||
*
|
*
|
||||||
|
|
|
@ -239,7 +239,7 @@ START_TEST(operation_prepare) {
|
||||||
Tset(loser, a, &three);
|
Tset(loser, a, &three);
|
||||||
Tset(prepared, b, &three);
|
Tset(prepared, b, &three);
|
||||||
|
|
||||||
Tprepare(prepared, a);
|
Tprepare(prepared); //, a);
|
||||||
|
|
||||||
Tset(prepared, b, &two);
|
Tset(prepared, b, &two);
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ START_TEST(operation_prepare) {
|
||||||
Tset(loser, a, &three);
|
Tset(loser, a, &three);
|
||||||
Tset(prepared, b, &three);
|
Tset(prepared, b, &three);
|
||||||
|
|
||||||
Tprepare(prepared, a);
|
Tprepare(prepared); //, a);
|
||||||
|
|
||||||
Tset(prepared, b, &two);
|
Tset(prepared, b, &two);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue