Implemented basic sub transaction support - seems to work so far, but I haven't
tested it heavily yet. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14432 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ca7c5a9e13
commit
9a99234b1a
@ -300,7 +300,7 @@ Journal::Journal(Volume *volume)
|
|||||||
fLogSize(volume->Log().length),
|
fLogSize(volume->Log().length),
|
||||||
fMaxTransactionSize(fLogSize / 4 - 5),
|
fMaxTransactionSize(fLogSize / 4 - 5),
|
||||||
fUsed(0),
|
fUsed(0),
|
||||||
fTransactionsInEntry(0)
|
fUnwrittenTransactions(0)
|
||||||
{
|
{
|
||||||
if (fMaxTransactionSize > fLogSize / 2)
|
if (fMaxTransactionSize > fLogSize / 2)
|
||||||
fMaxTransactionSize = fLogSize / 2 - 5;
|
fMaxTransactionSize = fLogSize / 2 - 5;
|
||||||
@ -501,13 +501,12 @@ Journal::_blockNotify(int32 transactionID, void *arg)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Journal::WriteLogEntry()
|
Journal::_WriteTransactionToLog()
|
||||||
{
|
{
|
||||||
// ToDo: in case of a failure, we need a backup plan like writing all
|
// ToDo: in case of a failure, we need a backup plan like writing all
|
||||||
// changed blocks back to disk immediately
|
// changed blocks back to disk immediately
|
||||||
|
|
||||||
fTransactionsInEntry = 0;
|
fUnwrittenTransactions = 0;
|
||||||
fHasChangedBlocks = false;
|
|
||||||
|
|
||||||
int32 blockShift = fVolume->BlockShift();
|
int32 blockShift = fVolume->BlockShift();
|
||||||
off_t logOffset = fVolume->ToBlock(fVolume->Log()) << blockShift;
|
off_t logOffset = fVolume->ToBlock(fVolume->Log()) << blockShift;
|
||||||
@ -679,8 +678,8 @@ Journal::FlushLogAndBlocks()
|
|||||||
|
|
||||||
// write the current log entry to disk
|
// write the current log entry to disk
|
||||||
|
|
||||||
if (fTransactionID != -1 /*&& TransactionSize() != 0*/) {
|
if (fUnwrittenTransactions != 0 && _TransactionSize() != 0) {
|
||||||
status = WriteLogEntry();
|
status = _WriteTransactionToLog();
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
FATAL(("writing current log entry failed: %s\n", strerror(status)));
|
FATAL(("writing current log entry failed: %s\n", strerror(status)));
|
||||||
}
|
}
|
||||||
@ -712,7 +711,12 @@ Journal::Lock(Transaction *owner)
|
|||||||
|
|
||||||
fOwner = owner;
|
fOwner = owner;
|
||||||
|
|
||||||
|
if (fUnwrittenTransactions > 0) {
|
||||||
|
// start a sub transaction
|
||||||
|
cache_start_sub_transaction(fVolume->BlockCache(), fTransactionID);
|
||||||
|
} else
|
||||||
fTransactionID = cache_start_transaction(fVolume->BlockCache());
|
fTransactionID = cache_start_transaction(fVolume->BlockCache());
|
||||||
|
|
||||||
if (fTransactionID < B_OK) {
|
if (fTransactionID < B_OK) {
|
||||||
fLock.Unlock();
|
fLock.Unlock();
|
||||||
return fTransactionID;
|
return fTransactionID;
|
||||||
@ -730,7 +734,6 @@ Journal::Unlock(Transaction *owner, bool success)
|
|||||||
// ToDo: what about failing transactions that do not unlock?
|
// ToDo: what about failing transactions that do not unlock?
|
||||||
_TransactionDone(success);
|
_TransactionDone(success);
|
||||||
|
|
||||||
fTransactionID = -1;
|
|
||||||
fTimestamp = system_time();
|
fTimestamp = system_time();
|
||||||
fOwner = NULL;
|
fOwner = NULL;
|
||||||
}
|
}
|
||||||
@ -739,40 +742,38 @@ Journal::Unlock(Transaction *owner, bool success)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
Journal::_TransactionSize() const
|
||||||
|
{
|
||||||
|
int32 count = cache_blocks_in_transaction(fVolume->BlockCache(), fTransactionID);
|
||||||
|
if (count < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Journal::_TransactionDone(bool success)
|
Journal::_TransactionDone(bool success)
|
||||||
{
|
{
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
if (_HasSubTransaction())
|
||||||
|
cache_abort_sub_transaction(fVolume->BlockCache(), fTransactionID);
|
||||||
|
else
|
||||||
cache_abort_transaction(fVolume->BlockCache(), fTransactionID);
|
cache_abort_transaction(fVolume->BlockCache(), fTransactionID);
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToDo:
|
|
||||||
/*
|
|
||||||
if (!success && fTransactionsInEntry == 0) {
|
|
||||||
// we can safely abort the transaction
|
|
||||||
sorted_array *array = fArray.Array();
|
|
||||||
if (array != NULL) {
|
|
||||||
// release the lock for all blocks in the array (we don't need
|
|
||||||
// to be notified when they are actually written to disk)
|
|
||||||
for (int32 i = 0; i < array->count; i++)
|
|
||||||
release_block(fVolume->Device(), array->values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fUnwrittenTransactions--;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Up to a maximum size, we will just batch several
|
// Up to a maximum size, we will just batch several
|
||||||
// transactions together to improve speed
|
// transactions together to improve speed
|
||||||
if (TransactionSize() < fMaxTransactionSize) {
|
if (_TransactionSize() < fMaxTransactionSize) {
|
||||||
fTransactionsInEntry++;
|
fUnwrittenTransactions++;
|
||||||
fHasChangedBlocks = false;
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return WriteLogEntry();
|
return _WriteTransactionToLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -785,7 +786,6 @@ Journal::LogBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks)
|
|||||||
if (TransactionSize() + numBlocks + 1 > fLogSize)
|
if (TransactionSize() + numBlocks + 1 > fLogSize)
|
||||||
return B_DEVICE_FULL;
|
return B_DEVICE_FULL;
|
||||||
|
|
||||||
fHasChangedBlocks = true;
|
|
||||||
int32 blockSize = fVolume->BlockSize();
|
int32 blockSize = fVolume->BlockSize();
|
||||||
|
|
||||||
for (;numBlocks-- > 0; blockNumber++, buffer += blockSize) {
|
for (;numBlocks-- > 0; blockNumber++, buffer += blockSize) {
|
||||||
|
@ -49,11 +49,9 @@ class Journal {
|
|||||||
|
|
||||||
status_t ReplayLog();
|
status_t ReplayLog();
|
||||||
|
|
||||||
status_t WriteLogEntry();
|
|
||||||
status_t LogBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks);
|
status_t LogBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks);
|
||||||
|
|
||||||
Transaction *CurrentTransaction() const { return fOwner; }
|
Transaction *CurrentTransaction() const { return fOwner; }
|
||||||
// uint32 TransactionSize() const { return fArray.CountItems() + fArray.BlocksUsed(); }
|
|
||||||
|
|
||||||
status_t FlushLogAndBlocks();
|
status_t FlushLogAndBlocks();
|
||||||
Volume *GetVolume() const { return fVolume; }
|
Volume *GetVolume() const { return fVolume; }
|
||||||
@ -62,6 +60,9 @@ class Journal {
|
|||||||
inline uint32 FreeLogBlocks() const;
|
inline uint32 FreeLogBlocks() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _HasSubTransaction() { return fUnwrittenTransactions > 1; }
|
||||||
|
uint32 _TransactionSize() const;
|
||||||
|
status_t _WriteTransactionToLog();
|
||||||
status_t _CheckRunArray(const run_array *array);
|
status_t _CheckRunArray(const run_array *array);
|
||||||
status_t _ReplayRunArray(int32 *start);
|
status_t _ReplayRunArray(int32 *start);
|
||||||
status_t _TransactionDone(bool success);
|
status_t _TransactionDone(bool success);
|
||||||
@ -71,10 +72,9 @@ class Journal {
|
|||||||
RecursiveLock fLock;
|
RecursiveLock fLock;
|
||||||
Transaction *fOwner;
|
Transaction *fOwner;
|
||||||
uint32 fLogSize, fMaxTransactionSize, fUsed;
|
uint32 fLogSize, fMaxTransactionSize, fUsed;
|
||||||
int32 fTransactionsInEntry;
|
int32 fUnwrittenTransactions;
|
||||||
SimpleLock fEntriesLock;
|
SimpleLock fEntriesLock;
|
||||||
LogEntryList fEntries;
|
LogEntryList fEntries;
|
||||||
bool fHasChangedBlocks;
|
|
||||||
bigtime_t fTimestamp;
|
bigtime_t fTimestamp;
|
||||||
int32 fTransactionID;
|
int32 fTransactionID;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user