* Replaced the specialized inode in transaction mechanism with a generic one.

That costs 12 more bytes per inode on 32 bit platforms, though.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35491 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-02-16 11:30:15 +00:00
parent 2a8ae7fb92
commit fd91cf4d18
7 changed files with 322 additions and 261 deletions

@ -3,6 +3,7 @@
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
//! block bitmap handling and allocation policies //! block bitmap handling and allocation policies

@ -3,7 +3,8 @@
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
//! inode access functions
//! Inode access functions
#include "Debug.h" #include "Debug.h"
@ -175,7 +176,7 @@ InodeAllocator::~InodeAllocator()
fInode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE); fInode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE);
// this unblocks any pending bfs_read_vnode() calls // this unblocks any pending bfs_read_vnode() calls
fInode->Free(*fTransaction); fInode->Free(*fTransaction);
fTransaction->RemoveInode(fInode); fTransaction->RemoveListener(fInode);
remove_vnode(volume->FSVolume(), fInode->ID()); remove_vnode(volume->FSVolume(), fInode->ID());
} else } else
@ -291,7 +292,7 @@ InodeAllocator::_TransactionListener(int32 id, int32 event, void* _inode)
status_t status_t
bfs_inode::InitCheck(Volume* volume) bfs_inode::InitCheck(Volume* volume) const
{ {
if (Magic1() != INODE_MAGIC1 if (Magic1() != INODE_MAGIC1
|| !(Flags() & INODE_IN_USE) || !(Flags() & INODE_IN_USE)
@ -403,7 +404,7 @@ Inode::~Inode()
status_t status_t
Inode::InitCheck(bool checkNode) Inode::InitCheck(bool checkNode) const
{ {
// test inode magic and flags // test inode magic and flags
if (checkNode) { if (checkNode) {
@ -437,6 +438,33 @@ Inode::InitCheck(bool checkNode)
} }
/*! Adds this inode to the specified transaction. This means that the inode will
be write locked until the transaction ended.
To ensure that the inode will stay valid until that point, an extra reference
is acquired to it as long as this transaction stays active.
*/
void
Inode::WriteLockInTransaction(Transaction& transaction)
{
// These flags can only change while holding the transaction lock
if ((Flags() & INODE_IN_TRANSACTION) != 0)
return;
// We share the same list link with the removed list, so we have to remove
// the inode from that list here (and add it back when we no longer need it)
if ((Flags() & INODE_DELETED) != 0)
fVolume->RemovedInodes().Remove(this);
if (!fVolume->IsInitializing())
acquire_vnode(fVolume->FSVolume(), ID());
rw_lock_write_lock(&Lock());
Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
transaction.AddListener(this);
}
status_t status_t
Inode::WriteBack(Transaction& transaction) Inode::WriteBack(Transaction& transaction)
{ {
@ -2379,6 +2407,35 @@ Inode::Sync()
} }
// #pragma mark - TransactionListener implementation
void
Inode::TransactionDone(bool success)
{
if (!success) {
// revert any changes made to the cached bfs_inode
UpdateNodeFromDisk();
}
}
void
Inode::RemovedFromTransaction()
{
Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
// See AddInode() why we do this here
if ((Flags() & INODE_DELETED) != 0)
fVolume->RemovedInodes().Add(this);
rw_lock_write_unlock(&Lock());
if (!fVolume->IsInitializing())
put_vnode(fVolume->FSVolume(), ID());
}
// #pragma mark - creation/deletion // #pragma mark - creation/deletion

@ -23,241 +23,245 @@ class NodeGetter;
class Transaction; class Transaction;
class Inode { class Inode : public TransactionListener {
typedef DoublyLinkedListLink<Inode> Link; typedef DoublyLinkedListLink<Inode> Link;
public: public:
Inode(Volume* volume, ino_t id); Inode(Volume* volume, ino_t id);
Inode(Volume* volume, Transaction& transaction, Inode(Volume* volume, Transaction& transaction,
ino_t id, mode_t mode, block_run& run); ino_t id, mode_t mode, block_run& run);
~Inode(); ~Inode();
ino_t ID() const { return fID; } status_t InitCheck(bool checkNode = true) const;
off_t BlockNumber() const
{ return fVolume->VnodeToBlock(fID); }
rw_lock& Lock() { return fLock; } ino_t ID() const { return fID; }
ReadLocker ReadLock() { return ReadLocker(fLock); } off_t BlockNumber() const
void WriteLockInTransaction(Transaction& transaction) { return fVolume->VnodeToBlock(fID); }
{ transaction.AddInode(this); }
recursive_lock& SmallDataLock() { return fSmallDataLock; } rw_lock& Lock() { return fLock; }
ReadLocker ReadLock() { return ReadLocker(fLock); }
void WriteLockInTransaction(Transaction& transaction);
status_t WriteBack(Transaction& transaction); recursive_lock& SmallDataLock() { return fSmallDataLock; }
void UpdateNodeFromDisk();
bool IsContainer() const status_t WriteBack(Transaction& transaction);
{ return S_ISDIR(Mode()); } void UpdateNodeFromDisk();
bool IsDirectory() const
{ return is_directory(Mode()); }
bool IsIndex() const
{ return is_index(Mode()); }
bool IsAttributeDirectory() const bool IsContainer() const
{ return (Mode() & S_EXTENDED_TYPES) { return S_ISDIR(Mode()); }
== S_ATTR_DIR; } bool IsDirectory() const
bool IsAttribute() const { return is_directory(Mode()); }
{ return (Mode() & S_EXTENDED_TYPES) bool IsIndex() const
== S_ATTR; } { return is_index(Mode()); }
bool IsFile() const
{ return (Mode()
& (S_IFMT | S_EXTENDED_TYPES)) == S_FILE; }
bool IsRegularNode() const
{ return (Mode() & S_EXTENDED_TYPES) == 0; }
// a regular node in the standard namespace
// (i.e. not an index or attribute)
bool IsSymLink() const { return S_ISLNK(Mode()); }
bool IsLongSymLink() const
{ return (Flags() & INODE_LONG_SYMLINK) != 0; }
bool HasUserAccessableStream() const { return IsFile(); } bool IsAttributeDirectory() const
// currently only files can be accessed with { return (Mode() & S_EXTENDED_TYPES)
// bfs_read()/bfs_write() == S_ATTR_DIR; }
bool NeedsFileCache() const bool IsAttribute() const
{ return IsFile() || IsAttribute() { return (Mode() & S_EXTENDED_TYPES)
|| IsLongSymLink(); } == S_ATTR; }
bool IsFile() const
{ return (Mode() & (S_IFMT
| S_EXTENDED_TYPES)) == S_FILE; }
bool IsRegularNode() const
{ return (Mode() & S_EXTENDED_TYPES) == 0; }
// a regular node in the standard namespace
// (i.e. not an index or attribute)
bool IsSymLink() const { return S_ISLNK(Mode()); }
bool IsLongSymLink() const
{ return (Flags() & INODE_LONG_SYMLINK)
!= 0; }
bool IsDeleted() const bool HasUserAccessableStream() const
{ return (Flags() & INODE_DELETED) != 0; } { return IsFile(); }
// currently only files can be accessed with
// bfs_read()/bfs_write()
bool NeedsFileCache() const
{ return IsFile() || IsAttribute()
|| IsLongSymLink(); }
mode_t Mode() const { return fNode.Mode(); } bool IsDeleted() const
uint32 Type() const { return fNode.Type(); } { return (Flags() & INODE_DELETED) != 0; }
int32 Flags() const { return fNode.Flags(); }
off_t Size() const { return fNode.data.Size(); } mode_t Mode() const { return fNode.Mode(); }
off_t AllocatedSize() const; uint32 Type() const { return fNode.Type(); }
off_t LastModified() const int32 Flags() const { return fNode.Flags(); }
{ return fNode.LastModifiedTime(); }
const block_run& BlockRun() const off_t Size() const { return fNode.data.Size(); }
{ return fNode.inode_num; } off_t AllocatedSize() const;
block_run& Parent() { return fNode.parent; } off_t LastModified() const
block_run& Attributes() { return fNode.attributes; } { return fNode.LastModifiedTime(); }
Volume* GetVolume() const { return fVolume; } const block_run& BlockRun() const
{ return fNode.inode_num; }
block_run& Parent() { return fNode.parent; }
block_run& Attributes() { return fNode.attributes; }
status_t InitCheck(bool checkNode = true); Volume* GetVolume() const { return fVolume; }
status_t CheckPermissions(int accessMode) const; status_t CheckPermissions(int accessMode) const;
// small_data access methods // small_data access methods
small_data* FindSmallData(const bfs_inode* node, small_data* FindSmallData(const bfs_inode* node,
const char* name) const; const char* name) const;
const char* Name(const bfs_inode* node) const; const char* Name(const bfs_inode* node) const;
status_t GetName(char* buffer, status_t GetName(char* buffer, size_t bufferSize
size_t bufferSize = B_FILE_NAME_LENGTH) const; = B_FILE_NAME_LENGTH) const;
status_t SetName(Transaction& transaction, const char* name); status_t SetName(Transaction& transaction,
const char* name);
// high-level attribute methods // high-level attribute methods
status_t ReadAttribute(const char* name, int32 type, status_t ReadAttribute(const char* name, int32 type,
off_t pos, uint8* buffer, size_t* _length); off_t pos, uint8* buffer, size_t* _length);
status_t WriteAttribute(Transaction& transaction, status_t WriteAttribute(Transaction& transaction,
const char* name, int32 type, off_t pos, const char* name, int32 type, off_t pos,
const uint8* buffer, size_t* _length, const uint8* buffer, size_t* _length,
bool* _created); bool* _created);
status_t RemoveAttribute(Transaction& transaction, status_t RemoveAttribute(Transaction& transaction,
const char* name); const char* name);
// attribute methods // attribute methods
status_t GetAttribute(const char* name, Inode** attribute); status_t GetAttribute(const char* name,
void ReleaseAttribute(Inode* attribute); Inode** _attribute);
status_t CreateAttribute(Transaction& transaction, void ReleaseAttribute(Inode* attribute);
const char* name, uint32 type, status_t CreateAttribute(Transaction& transaction,
Inode** attribute); const char* name, uint32 type,
Inode** attribute);
// for directories only: // for directories only:
BPlusTree* Tree() const { return fTree; } BPlusTree* Tree() const { return fTree; }
bool IsEmpty(); bool IsEmpty();
status_t ContainerContentsChanged(Transaction& transaction); status_t ContainerContentsChanged(
Transaction& transaction);
// manipulating the data stream // manipulating the data stream
status_t FindBlockRun(off_t pos, block_run& run, status_t FindBlockRun(off_t pos, block_run& run,
off_t& offset); off_t& offset);
status_t ReadAt(off_t pos, uint8* buffer, size_t* length); status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
status_t WriteAt(Transaction& transaction, off_t pos, status_t WriteAt(Transaction& transaction, off_t pos,
const uint8* buffer, size_t* length); const uint8* buffer, size_t* length);
status_t FillGapWithZeros(off_t oldSize, off_t newSize); status_t FillGapWithZeros(off_t oldSize, off_t newSize);
status_t SetFileSize(Transaction& transaction, off_t size); status_t SetFileSize(Transaction& transaction,
status_t Append(Transaction& transaction, off_t bytes); off_t size);
status_t TrimPreallocation(Transaction& transaction); status_t Append(Transaction& transaction, off_t bytes);
bool NeedsTrimming() const; status_t TrimPreallocation(Transaction& transaction);
bool NeedsTrimming() const;
status_t Free(Transaction& transaction); status_t Free(Transaction& transaction);
status_t Sync(); status_t Sync();
bfs_inode& Node() { return fNode; } bfs_inode& Node() { return fNode; }
const bfs_inode& Node() const { return fNode; } const bfs_inode& Node() const { return fNode; }
// create/remove inodes // create/remove inodes
status_t Remove(Transaction& transaction, const char* name, status_t Remove(Transaction& transaction,
ino_t* _id = NULL, bool isDirectory = false, const char* name, ino_t* _id = NULL,
bool force = false); bool isDirectory = false,
static status_t Create(Transaction& transaction, Inode* parent, bool force = false);
const char* name, int32 mode, int openMode, static status_t Create(Transaction& transaction, Inode* parent,
uint32 type, bool* _created = NULL, const char* name, int32 mode, int openMode,
ino_t* _id = NULL, Inode** _inode = NULL, uint32 type, bool* _created = NULL,
fs_vnode_ops* vnodeOps = NULL, ino_t* _id = NULL, Inode** _inode = NULL,
uint32 publishFlags = 0); fs_vnode_ops* vnodeOps = NULL,
uint32 publishFlags = 0);
// index maintaining helper // index maintaining helper
void UpdateOldSize() { fOldSize = Size(); } void UpdateOldSize() { fOldSize = Size(); }
void UpdateOldLastModified() void UpdateOldLastModified()
{ fOldLastModified { fOldLastModified
= Node().LastModifiedTime(); } = Node().LastModifiedTime(); }
off_t OldSize() { return fOldSize; } off_t OldSize() { return fOldSize; }
off_t OldLastModified() { return fOldLastModified; } off_t OldLastModified() { return fOldLastModified; }
bool InNameIndex() const; bool InNameIndex() const;
bool InSizeIndex() const; bool InSizeIndex() const;
bool InLastModifiedIndex() const; bool InLastModifiedIndex() const;
// file cache // file cache
void* FileCache() const { return fCache; } void* FileCache() const { return fCache; }
void SetFileCache(void* cache) { fCache = cache; } void SetFileCache(void* cache) { fCache = cache; }
void* Map() const { return fMap; } void* Map() const { return fMap; }
void SetMap(void* map) { fMap = map; } void SetMap(void* map) { fMap = map; }
#if _KERNEL_MODE && KDEBUG #if _KERNEL_MODE && KDEBUG
void AssertReadLocked() void AssertReadLocked()
{ ASSERT_READ_LOCKED_RW_LOCK(&fLock); } { ASSERT_READ_LOCKED_RW_LOCK(&fLock); }
void AssertWriteLocked() void AssertWriteLocked()
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); } { ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
#endif #endif
#ifdef B_HAIKU_64_BIT Link* GetDoublyLinkedListLink()
Link* GetDoublyLinkedListLink() { return (Link*)TransactionListener
{ return &fListLink; } ::GetDoublyLinkedListLink(); }
const Link* GetDoublyLinkedListLink() const const Link* GetDoublyLinkedListLink() const
{ return &fListLink; } { return (Link*)TransactionListener
#else ::GetDoublyLinkedListLink(); }
Link* GetDoublyLinkedListLink()
{ return (Link*)&fNode.pad[0]; } protected:
const Link* GetDoublyLinkedListLink() const virtual void TransactionDone(bool success);
{ return (Link*)&fNode.pad[0]; } virtual void RemovedFromTransaction();
#endif
private: private:
Inode(const Inode& other); Inode(const Inode& other);
Inode& operator=(const Inode& other); Inode& operator=(const Inode& other);
// no implementation // no implementation
friend class AttributeIterator; friend class AttributeIterator;
friend class InodeAllocator; friend class InodeAllocator;
// small_data access methods // small_data access methods
status_t _MakeSpaceForSmallData(Transaction& transaction, status_t _MakeSpaceForSmallData(Transaction& transaction,
bfs_inode* node, const char* name, bfs_inode* node, const char* name,
int32 length); int32 length);
status_t _RemoveSmallData(Transaction& transaction, status_t _RemoveSmallData(Transaction& transaction,
NodeGetter& node, const char* name); NodeGetter& node, const char* name);
status_t _AddSmallData(Transaction& transaction, status_t _AddSmallData(Transaction& transaction,
NodeGetter& node, const char* name, uint32 type, NodeGetter& node, const char* name,
off_t pos, const uint8* data, size_t length, uint32 type, off_t pos, const uint8* data,
bool force = false); size_t length, bool force = false);
status_t _GetNextSmallData(bfs_inode* node, status_t _GetNextSmallData(bfs_inode* node,
small_data** _smallData) const; small_data** _smallData) const;
status_t _RemoveSmallData(bfs_inode* node, small_data* item, status_t _RemoveSmallData(bfs_inode* node,
int32 index); small_data* item, int32 index);
status_t _RemoveAttribute(Transaction& transaction, status_t _RemoveAttribute(Transaction& transaction,
const char* name, bool hasIndex, Index* index); const char* name, bool hasIndex,
Index* index);
void _AddIterator(AttributeIterator* iterator); void _AddIterator(AttributeIterator* iterator);
void _RemoveIterator(AttributeIterator* iterator); void _RemoveIterator(AttributeIterator* iterator);
size_t _DoubleIndirectBlockLength() const; size_t _DoubleIndirectBlockLength() const;
status_t _FreeStaticStreamArray(Transaction& transaction, status_t _FreeStaticStreamArray(Transaction& transaction,
int32 level, block_run run, off_t size, int32 level, block_run run, off_t size,
off_t offset, off_t& max); off_t offset, off_t& max);
status_t _FreeStreamArray(Transaction& transaction, status_t _FreeStreamArray(Transaction& transaction,
block_run* array, uint32 arrayLength, block_run* array, uint32 arrayLength,
off_t size, off_t& offset, off_t& max); off_t size, off_t& offset, off_t& max);
status_t _AllocateBlockArray(Transaction& transaction, status_t _AllocateBlockArray(Transaction& transaction,
block_run& run, size_t length, block_run& run, size_t length,
bool variableSize = false); bool variableSize = false);
status_t _GrowStream(Transaction& transaction, off_t size); status_t _GrowStream(Transaction& transaction,
status_t _ShrinkStream(Transaction& transaction, off_t size); off_t size);
status_t _ShrinkStream(Transaction& transaction,
off_t size);
private: private:
rw_lock fLock; rw_lock fLock;
Volume* fVolume; Volume* fVolume;
ino_t fID; ino_t fID;
BPlusTree* fTree; BPlusTree* fTree;
Inode* fAttributes; Inode* fAttributes;
void* fCache; void* fCache;
void* fMap; void* fMap;
bfs_inode fNode; bfs_inode fNode;
off_t fOldSize; off_t fOldSize;
off_t fOldLastModified; off_t fOldLastModified;
// we need those values to ensure we will remove // we need those values to ensure we will remove
// the correct keys from the indices // the correct keys from the indices
#ifdef B_HAIKU_64_BIT
Link fListLink;
#endif
mutable recursive_lock fSmallDataLock; mutable recursive_lock fSmallDataLock;
SinglyLinkedList<AttributeIterator> fIterators; SinglyLinkedList<AttributeIterator> fIterators;
}; };

@ -1,8 +1,9 @@
/* /*
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
//! Transaction and logging //! Transaction and logging
@ -1005,7 +1006,7 @@ Journal::Unlock(Transaction* owner, bool success)
// closed. // closed.
bool separateSubTransactions = fSeparateSubTransactions; bool separateSubTransactions = fSeparateSubTransactions;
fSeparateSubTransactions = true; fSeparateSubTransactions = true;
owner->UnlockInodes(success); owner->NotifyListeners(success);
fSeparateSubTransactions = separateSubTransactions; fSeparateSubTransactions = separateSubTransactions;
fOwner = owner->Parent(); fOwner = owner->Parent();
@ -1018,7 +1019,7 @@ Journal::Unlock(Transaction* owner, bool success)
&& recursive_lock_get_recursion(&fLock) == 1) && recursive_lock_get_recursion(&fLock) == 1)
fSeparateSubTransactions = false; fSeparateSubTransactions = false;
} else } else
owner->MoveInodesTo(fOwner); owner->MoveListenersTo(fOwner);
recursive_lock_unlock(&fLock); recursive_lock_unlock(&fLock);
return B_OK; return B_OK;
@ -1077,6 +1078,7 @@ Journal::_TransactionDone(bool success)
#ifdef BFS_DEBUGGER_COMMANDS #ifdef BFS_DEBUGGER_COMMANDS
void void
Journal::Dump() Journal::Dump()
{ {
@ -1121,9 +1123,23 @@ dump_journal(int argc, char** argv)
return 0; return 0;
} }
#endif // BFS_DEBUGGER_COMMANDS #endif // BFS_DEBUGGER_COMMANDS
// #pragma mark - TransactionListener
TransactionListener::TransactionListener()
{
}
TransactionListener::~TransactionListener()
{
}
// #pragma mark - Transaction // #pragma mark - Transaction
@ -1143,74 +1159,33 @@ Transaction::Start(Volume* volume, off_t refBlock)
} }
/*! Adds an inode to this transaction. This means that the inode will be write
locked until the transaction ended.
To ensure that the inode will stay valid until that point, an extra reference
is acquired to it as long as this transaction stays active.
*/
void void
Transaction::AddInode(Inode* inode) Transaction::AddListener(TransactionListener* listener)
{ {
if (fJournal == NULL) if (fJournal == NULL)
panic("Transaction is not running!"); panic("Transaction is not running!");
// These flags can only change while holding the transaction lock fListeners.Add(listener);
if ((inode->Flags() & INODE_IN_TRANSACTION) != 0)
return;
// We share the same list link with the removed list, so we have to remove
// the inode from that list here (and add it back when we no longer need it)
if ((inode->Flags() & INODE_DELETED) != 0)
GetVolume()->RemovedInodes().Remove(inode);
if (!GetVolume()->IsInitializing())
acquire_vnode(GetVolume()->FSVolume(), inode->ID());
rw_lock_write_lock(&inode->Lock());
fLockedInodes.Add(inode);
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
} }
void void
Transaction::RemoveInode(Inode* inode) Transaction::RemoveListener(TransactionListener* listener)
{ {
if (fJournal == NULL) if (fJournal == NULL)
panic("Transaction is not running!"); panic("Transaction is not running!");
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION); fListeners.Remove(listener);
fLockedInodes.Remove(inode); listener->RemovedFromTransaction();
rw_lock_write_unlock(&inode->Lock());
// See AddInode() why we do this here
if ((inode->Flags() & INODE_DELETED) != 0)
GetVolume()->RemovedInodes().Add(inode);
if (!GetVolume()->IsInitializing())
put_vnode(GetVolume()->FSVolume(), inode->ID());
} }
void void
Transaction::UnlockInodes(bool success) Transaction::NotifyListeners(bool success)
{ {
while (Inode* inode = fLockedInodes.RemoveHead()) { while (TransactionListener* listener = fListeners.RemoveHead()) {
if (success) { listener->TransactionDone(success);
inode->Node().flags listener->RemovedFromTransaction();
&= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
} else {
// revert any changes made to the cached bfs_inode
inode->UpdateNodeFromDisk();
}
rw_lock_write_unlock(&inode->Lock());
// See AddInode() why we do this here
if ((inode->Flags() & INODE_DELETED) != 0)
GetVolume()->RemovedInodes().Add(inode);
if (!GetVolume()->IsInitializing())
put_vnode(GetVolume()->FSVolume(), inode->ID());
} }
} }
@ -1219,9 +1194,9 @@ Transaction::UnlockInodes(bool success)
sure they will still be reverted in case the transaction is aborted. sure they will still be reverted in case the transaction is aborted.
*/ */
void void
Transaction::MoveInodesTo(Transaction* transaction) Transaction::MoveListenersTo(Transaction* transaction)
{ {
while (Inode* inode = fLockedInodes.RemoveHead()) { while (TransactionListener* listener = fListeners.RemoveHead()) {
transaction->fLockedInodes.Add(inode); transaction->fListeners.Add(listener);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
#ifndef JOURNAL_H #ifndef JOURNAL_H
@ -86,6 +86,19 @@ Journal::FreeLogBlocks() const
} }
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 { class Transaction {
public: public:
Transaction(Volume* volume, off_t refBlock) Transaction(Volume* volume, off_t refBlock)
@ -176,11 +189,11 @@ public:
int32 ID() const int32 ID() const
{ return fJournal->TransactionID(); } { return fJournal->TransactionID(); }
void AddInode(Inode* inode); void AddListener(TransactionListener* listener);
void RemoveInode(Inode* inode); void RemoveListener(TransactionListener* listener);
void UnlockInodes(bool success); void NotifyListeners(bool success);
void MoveInodesTo(Transaction* transaction); void MoveListenersTo(Transaction* transaction);
void SetParent(Transaction* parent) void SetParent(Transaction* parent)
{ fParent = parent; } { fParent = parent; }
@ -192,13 +205,15 @@ private:
Transaction& operator=(const Transaction& other); Transaction& operator=(const Transaction& other);
// no implementation // no implementation
Journal* fJournal; Journal* fJournal;
InodeList fLockedInodes; TransactionListeners fListeners;
Transaction* fParent; Transaction* fParent;
}; };
#ifdef BFS_DEBUGGER_COMMANDS #ifdef BFS_DEBUGGER_COMMANDS
int dump_journal(int argc, char** argv); int dump_journal(int argc, char** argv);
#endif #endif
#endif // JOURNAL_H #endif // JOURNAL_H

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
#ifndef VOLUME_H #ifndef VOLUME_H
@ -11,10 +11,12 @@
#include "bfs.h" #include "bfs.h"
#include "BlockAllocator.h" #include "BlockAllocator.h"
class Journal; class Journal;
class Inode; class Inode;
class Query; class Query;
enum volume_flags { enum volume_flags {
VOLUME_READ_ONLY = 0x0001 VOLUME_READ_ONLY = 0x0001
}; };
@ -25,6 +27,7 @@ enum volume_initialize_flags {
typedef DoublyLinkedList<Inode> InodeList; typedef DoublyLinkedList<Inode> InodeList;
class Volume { class Volume {
public: public:
Volume(fs_volume* volume); Volume(fs_volume* volume);

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
* Parts of this code is based on work previously done by Marcus Overhagen. * Parts of this code is based on work previously done by Marcus Overhagen.
* *
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
@ -7,6 +7,7 @@
#ifndef BFS_H #ifndef BFS_H
#define BFS_H #define BFS_H
//! BFS definitions and helper functions //! BFS definitions and helper functions
@ -144,20 +145,25 @@ struct data_stream {
struct bfs_inode; struct bfs_inode;
struct small_data { struct small_data {
uint32 type; uint32 type;
uint16 name_size; uint16 name_size;
uint16 data_size; uint16 data_size;
char name[0]; // name_size long, followed by data char name[0]; // name_size long, followed by data
uint32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); } uint32 Type() const
uint16 NameSize() const { return BFS_ENDIAN_TO_HOST_INT16(name_size); } { return BFS_ENDIAN_TO_HOST_INT32(type); }
uint16 DataSize() const { return BFS_ENDIAN_TO_HOST_INT16(data_size); } uint16 NameSize() const
{ return BFS_ENDIAN_TO_HOST_INT16(
name_size); }
uint16 DataSize() const
{ return BFS_ENDIAN_TO_HOST_INT16(
data_size); }
inline char *Name() const; inline char* Name() const;
inline uint8 *Data() const; inline uint8* Data() const;
inline uint32 Size() const; inline uint32 Size() const;
inline small_data *Next() const; inline small_data* Next() const;
inline bool IsLast(const bfs_inode *inode) const; inline bool IsLast(const bfs_inode* inode) const;
} _PACKED; } _PACKED;
// the file name is part of the small_data structure // the file name is part of the small_data structure
@ -222,7 +228,7 @@ struct bfs_inode {
{ return BFS_ENDIAN_TO_HOST_INT64(status_change_time); } { return BFS_ENDIAN_TO_HOST_INT64(status_change_time); }
small_data* SmallDataStart() { return small_data_start; } small_data* SmallDataStart() { return small_data_start; }
status_t InitCheck(Volume *volume); status_t InitCheck(Volume* volume) const;
// defined in Inode.cpp // defined in Inode.cpp
static int64 ToInode(bigtime_t time) static int64 ToInode(bigtime_t time)