* Copyright 2001-2012, Axel DΓΆrfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
#ifndef JOURNAL_H
#define JOURNAL_H
#include "system_dependencies.h"
#include "Volume.h"
#include "Utility.h"
struct run_array;
class Inode;
class LogEntry;
typedef DoublyLinkedList<LogEntry> LogEntryList;
class Journal {
public:
Journal(Volume* volume);
~Journal();
status_t InitCheck();
status_t Lock(Transaction* owner,
bool separateSubTransactions);
status_t Unlock(Transaction* owner, bool success);
status_t ReplayLog();
Transaction* CurrentTransaction() const { return fOwner; }
size_t CurrentTransactionSize() const;
bool CurrentTransactionTooLarge() const;
status_t FlushLogAndBlocks();
Volume* GetVolume() const { return fVolume; }
int32 TransactionID() const { return fTransactionID; }
inline uint32 FreeLogBlocks() const;
#ifdef BFS_DEBUGGER_COMMANDS
void Dump();
#endif
private:
bool _HasSubTransaction() const
{ return fHasSubtransaction; }
status_t _FlushLog(bool canWait, bool flushBlocks);
uint32 _TransactionSize() const;
status_t _WriteTransactionToLog();
status_t _CheckRunArray(const run_array* array);
status_t _ReplayRunArray(int32* start);
status_t _TransactionDone(bool success);
static void _TransactionWritten(int32 transactionID,
int32 event, void* _logEntry);
static void _TransactionIdle(int32 transactionID, int32 event,
void* _journal);
static status_t _FlushLog(void* _journal);
private:
Volume* fVolume;
recursive_lock fLock;
Transaction* fOwner;
uint32 fLogSize;
uint32 fMaxTransactionSize;
uint32 fUsed;
int32 fUnwrittenTransactions;
mutex fEntriesLock;
LogEntryList fEntries;
bigtime_t fTimestamp;
int32 fTransactionID;
bool fHasSubtransaction;
bool fSeparateSubTransactions;
};
inline uint32
Journal::FreeLogBlocks() const
{
return fVolume->LogStart() <= fVolume->LogEnd()
? fLogSize - fVolume->LogEnd() + fVolume->LogStart()
: fVolume->LogStart() - fVolume->LogEnd();
}
class TransactionListener
: public DoublyLinkedListLinkImpl<TransactionListener> {
public:
TransactionListener();
virtual ~TransactionListener();
virtual void TransactionDone(bool success) = 0;
virtual void RemovedFromTransaction() = 0;
};
typedef DoublyLinkedList<TransactionListener> TransactionListeners;
class Transaction {
public:
Transaction(Volume* volume, off_t refBlock)
:
fJournal(NULL),
fParent(NULL)
{
Start(volume, refBlock);
}
Transaction(Volume* volume, block_run refRun)
:
fJournal(NULL),
fParent(NULL)
{
Start(volume, volume->ToBlock(refRun));
}
Transaction()
:
fJournal(NULL),
fParent(NULL)
{
}
~Transaction()
{
if (fJournal != NULL)
fJournal->Unlock(this, false);
}
status_t Start(Volume* volume, off_t refBlock);
bool IsStarted() const { return fJournal != NULL; }
status_t Done()
{
status_t status = B_OK;
if (fJournal != NULL) {
status = fJournal->Unlock(this, true);
if (status == B_OK)
fJournal = NULL;
}
return status;
}
bool HasParent() const
{
return fParent != NULL;
}
bool IsTooLarge() const
{
return fJournal->CurrentTransactionTooLarge();
}
status_t WriteBlocks(off_t blockNumber, const uint8* buffer,
size_t numBlocks = 1)
{
if (fJournal == NULL)
return B_NO_INIT;
void* cache = GetVolume()->BlockCache();
size_t blockSize = GetVolume()->BlockSize();
for (size_t i = 0; i < numBlocks; i++) {
void* block = block_cache_get_empty(cache, blockNumber + i,
ID());
if (block == NULL)
return B_ERROR;
memcpy(block, buffer, blockSize);
buffer += blockSize;
block_cache_put(cache, blockNumber + i);
}
return B_OK;
}
Volume* GetVolume() const
{ return fJournal != NULL ? fJournal->GetVolume() : NULL; }
int32 ID() const
{ return fJournal->TransactionID(); }
void AddListener(TransactionListener* listener);
void RemoveListener(TransactionListener* listener);
void NotifyListeners(bool success);
void MoveListenersTo(Transaction* transaction);
void SetParent(Transaction* parent)
{ fParent = parent; }
Transaction* Parent() const
{ return fParent; }
private:
Transaction(const Transaction& other);
Transaction& operator=(const Transaction& other);
Journal* fJournal;
TransactionListeners fListeners;
Transaction* fParent;
};
#ifdef BFS_DEBUGGER_COMMANDS
int dump_journal(int argc, char** argv);
#endif
#endif