Added node monitoring support.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37601 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-07-19 15:31:08 +00:00
parent cc2a443dbd
commit e828231248
10 changed files with 368 additions and 17 deletions

View File

@ -169,8 +169,11 @@ File::Read(off_t pos, void* buffer, size_t size, size_t& _bytesRead)
status_t
File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten,
bool& _sizeChanged)
{
_sizeChanged = false;
if (size == 0) {
_bytesWritten = 0;
return B_OK;
@ -208,6 +211,8 @@ File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
error = transaction.Commit();
if (error != B_OK)
RETURN_ERROR(error);
_sizeChanged = true;
}
// now the file has the right size -- do the write

View File

@ -28,7 +28,8 @@ public:
virtual status_t Read(off_t pos, void* buffer, size_t size,
size_t& _bytesRead);
virtual status_t Write(off_t pos, const void* buffer,
size_t size, size_t& _bytesWritten);
size_t size, size_t& _bytesWritten,
bool& _sizeChanged);
virtual status_t Sync();
virtual void RevertNodeData(const checksumfs_node& nodeData);

View File

@ -22,6 +22,7 @@ HAIKU_CHECKSUM_FS_SOURCES =
Directory.cpp
File.cpp
Node.cpp
Notifications.cpp
SuperBlock.cpp
SymLink.cpp
Transaction.cpp

View File

@ -99,7 +99,8 @@ Node::Read(off_t pos, void* buffer, size_t size, size_t& _bytesRead)
status_t
Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten,
bool& _sizeChanged)
{
RETURN_ERROR(B_BAD_VALUE);
}

View File

@ -42,7 +42,8 @@ public:
virtual status_t Read(off_t pos, void* buffer, size_t size,
size_t& _bytesRead);
virtual status_t Write(off_t pos, const void* buffer,
size_t size, size_t& _bytesWritten);
size_t size, size_t& _bytesWritten,
bool& _sizeChanged);
virtual status_t Sync();
inline const checksumfs_node& NodeData() const { return fNode; }

View File

@ -0,0 +1,117 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Notifications.h"
#include "Directory.h"
#include "Volume.h"
// #pragma mark - EntryCreatedNotification
EntryCreatedNotification::EntryCreatedNotification(Directory* directory,
const char* name, Node* node)
:
fDirectory(directory),
fName(name),
fNode(node)
{
}
void
EntryCreatedNotification::NotifyPostCommit() const
{
notify_entry_created(fDirectory->GetVolume()->ID(),
fDirectory->BlockIndex(), fName, fNode->BlockIndex());
}
// #pragma mark - EntryRemovedNotification
EntryRemovedNotification::EntryRemovedNotification(Directory* directory,
const char* name, Node* node)
:
fDirectory(directory),
fName(name),
fNode(node)
{
}
void
EntryRemovedNotification::NotifyPostCommit() const
{
notify_entry_removed(fDirectory->GetVolume()->ID(),
fDirectory->BlockIndex(), fName, fNode->BlockIndex());
}
// #pragma mark - EntryMovedNotification
EntryMovedNotification::EntryMovedNotification(Directory* fromDirectory,
const char* fromName, Directory* toDirectory, const char* toName,
Node* node)
:
fFromDirectory(fromDirectory),
fFromName(fromName),
fToDirectory(toDirectory),
fToName(toName),
fNode(node)
{
}
void
EntryMovedNotification::NotifyPostCommit() const
{
notify_entry_moved(fFromDirectory->GetVolume()->ID(),
fFromDirectory->BlockIndex(), fFromName, fToDirectory->BlockIndex(),
fToName, fNode->BlockIndex());
}
// #pragma mark - StatChangedNotification
StatChangedNotification::StatChangedNotification(Node* node, uint32 statFields)
:
fNode(node),
fStatFields(statFields)
{
}
void
StatChangedNotification::NotifyPostCommit() const
{
notify_stat_changed(fNode->GetVolume()->ID(), fNode->BlockIndex(),
fStatFields);
}
// #pragma mark - AttributeChangedNotification
AttributeChangedNotification::AttributeChangedNotification(Node* node,
const char* attribute, int32 cause)
:
fNode(node),
fAttribute(attribute),
fCause(cause)
{
}
void
AttributeChangedNotification::NotifyPostCommit() const
{
notify_attribute_changed(fNode->GetVolume()->ID(), fNode->BlockIndex(),
fAttribute, fCause);
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef NOTIFICATIONS_H
#define NOTIFICATIONS_H
#include "Transaction.h"
class Directory;
class EntryCreatedNotification : public PostCommitNotification {
public:
EntryCreatedNotification(Directory* directory,
const char* name, Node* node);
virtual void NotifyPostCommit() const;
private:
Directory* fDirectory;
const char* fName;
Node* fNode;
};
class EntryRemovedNotification : public PostCommitNotification {
public:
EntryRemovedNotification(Directory* directory,
const char* name, Node* node);
virtual void NotifyPostCommit() const;
private:
Directory* fDirectory;
const char* fName;
Node* fNode;
};
class EntryMovedNotification : public PostCommitNotification {
public:
EntryMovedNotification(Directory* fromDirectory,
const char* fromName,
Directory* toDirectory, const char* toName,
Node* node);
virtual void NotifyPostCommit() const;
private:
Directory* fFromDirectory;
const char* fFromName;
Directory* fToDirectory;
const char* fToName;
Node* fNode;
};
class StatChangedNotification : public PostCommitNotification {
public:
StatChangedNotification(Node* node,
uint32 statFields);
virtual void NotifyPostCommit() const;
private:
Node* fNode;
uint32 fStatFields;
};
class AttributeChangedNotification : public PostCommitNotification {
public:
AttributeChangedNotification(Node* node,
const char* attribute, int32 cause);
virtual void NotifyPostCommit() const;
private:
Node* fNode;
const char* fAttribute;
int32 fCause;
};
#endif // NOTIFICATIONS_H

View File

@ -71,7 +71,7 @@ Transaction::StartAndAddNode(Node* node, uint32 flags = 0)
status_t
Transaction::Commit()
Transaction::Commit(const PostCommitNotification* notification)
{
ASSERT(fID >= 0);
@ -93,6 +93,10 @@ Transaction::Commit()
return error;
}
// send notifications
if (notification != NULL)
notification->NotifyPostCommit();
// clean up
_DeleteNodeInfosAndUnlock(false);
@ -206,3 +210,12 @@ Transaction::_DeleteNodeInfosAndUnlock(bool failed)
delete info;
}
}
// #pragma mark - PostCommitNotification
PostCommitNotification::~PostCommitNotification()
{
}

View File

@ -13,6 +13,7 @@
#include "Node.h"
class PostCommitNotification;
class Volume;
@ -32,7 +33,11 @@ public:
status_t Start();
status_t StartAndAddNode(Node* node, uint32 flags = 0);
status_t Commit();
status_t Commit(
const PostCommitNotification* notification
= NULL);
inline status_t Commit(
const PostCommitNotification& notification);
void Abort();
status_t AddNode(Node* node, uint32 flags = 0);
@ -62,4 +67,22 @@ private:
};
status_t
Transaction::Commit(const PostCommitNotification& notification)
{
return Commit(&notification);
}
// #pragma mark -
class PostCommitNotification {
public:
virtual ~PostCommitNotification();
virtual void NotifyPostCommit() const = 0;
};
#endif // TRANSACTION_H

View File

@ -19,12 +19,14 @@
#include <AutoLocker.h>
#include <debug.h>
#include <util/AutoLock.h>
#include "checksumfs.h"
#include "checksumfs_private.h"
#include "DebugSupport.h"
#include "Directory.h"
#include "File.h"
#include "Notifications.h"
#include "SuperBlock.h"
#include "SymLink.h"
#include "Transaction.h"
@ -35,17 +37,99 @@ static const char* const kCheckSumFSModuleName = "file_systems/checksumfs"
B_CURRENT_FS_API_VERSION;
static const char* const kCheckSumFSShortName = "checksumfs";
static const bigtime_t kModifiedInterimUpdateInterval = 500000;
// wait at least 0.5s between interim modified updates
// #pragma mark -
struct FileCookie {
int openMode;
mutex lock;
int openMode;
bigtime_t lastModifiedUpdate;
bool modifiedNeedsUpdate;
bool sizeChangedSinceUpdate;
bool modifiedNeedsFinalUpdate;
bool finalSizeChanged;
FileCookie(int openMode)
:
openMode(openMode)
openMode(openMode),
lastModifiedUpdate(0),
modifiedNeedsUpdate(false),
sizeChangedSinceUpdate(false),
modifiedNeedsFinalUpdate(false),
finalSizeChanged(false)
{
mutex_init(&lock, "checksumfs file cookie");
}
~FileCookie()
{
mutex_destroy(&lock);
}
status_t UpdateModifiedIfNecessary(Node* node, bool finalUpdate)
{
MutexLocker locker(lock);
return _UpdateModifiedIfNecessary(node, finalUpdate);
}
status_t FileModified(Node* node, bool sizeChanged)
{
MutexLocker locker(lock);
modifiedNeedsUpdate = true;
modifiedNeedsFinalUpdate = true;
sizeChangedSinceUpdate |= sizeChanged;
finalSizeChanged |= sizeChanged;
return _UpdateModifiedIfNecessary(node, false);
}
private:
status_t _UpdateModifiedIfNecessary(Node* node, bool finalUpdate)
{
uint32 statFlags = B_STAT_MODIFICATION_TIME | B_STAT_CHANGE_TIME;
if (finalUpdate) {
if (!modifiedNeedsFinalUpdate)
return B_OK;
if (finalSizeChanged)
statFlags |= B_STAT_SIZE;
} else {
if (!modifiedNeedsUpdate)
return B_OK;
if (system_time()
< lastModifiedUpdate + kModifiedInterimUpdateInterval) {
// not enough time passed -- postpone update
return B_OK;
}
statFlags |= B_STAT_INTERIM_UPDATE
| (sizeChangedSinceUpdate ? B_STAT_SIZE : 0);
}
// do the update -- start a transaction, lock the node, and update
Transaction transaction(node->GetVolume());
status_t error = transaction.StartAndAddNode(node);
if (error != B_OK)
return error;
node->Touched(NODE_MODIFIED);
error = transaction.Commit(StatChangedNotification(node, statFlags));
if (error != B_OK)
return error;
modifiedNeedsUpdate = false;
lastModifiedUpdate = system_time();
return B_OK;
}
};
@ -308,7 +392,8 @@ remove_entry(fs_volume* fsVolume, fs_vnode* parent, const char* name,
}
// commit the transaction
return transaction.Commit();
return transaction.Commit(EntryRemovedNotification(directory, name,
childNode));
}
@ -723,7 +808,8 @@ checksumfs_create_symlink(fs_volume* fsVolume, fs_vnode* parent,
directory->Touched(NODE_MODIFIED);
// commit the transaction
return transaction.Commit();
return transaction.Commit(EntryCreatedNotification(directory, name,
newSymLink));
}
@ -773,7 +859,7 @@ checksumfs_link(fs_volume* fsVolume, fs_vnode* dir, const char* name,
directory->Touched(NODE_MODIFIED);
// commit the transaction
return transaction.Commit();
return transaction.Commit(EntryCreatedNotification(directory, name, node));
}
@ -896,7 +982,8 @@ checksumfs_rename(fs_volume* fsVolume, fs_vnode* fromDir, const char* fromName,
toDirectory->Touched(NODE_MODIFIED);
// commit the transaction
return transaction.Commit();
return transaction.Commit(EntryMovedNotification(fromDirectory, fromName,
toDirectory, toName, node));
}
@ -1027,7 +1114,7 @@ checksumfs_write_stat(fs_volume* fsVolume, fs_vnode* vnode,
node->Touched(NODE_ACCESSED);
// commit the transaction
return transaction.Commit();
return transaction.Commit(StatChangedNotification(node, statMask));
}
@ -1231,7 +1318,8 @@ checksumfs_create(fs_volume* fsVolume, fs_vnode* parent, const char* name,
transaction.KeepNode(newFile);
// commit the transaction
error = transaction.Commit();
error = transaction.Commit(EntryCreatedNotification(directory, name,
newFile));
if (error != B_OK) {
volume->RemoveNode(newFile);
delete newFile;
@ -1281,6 +1369,10 @@ static status_t
checksumfs_free_cookie(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie)
{
FileCookie* cookie = (FileCookie*)_cookie;
Node* node = (Node*)vnode->private_node;
cookie->UpdateModifiedIfNecessary(node, true);
delete cookie;
return B_OK;
}
@ -1330,8 +1422,16 @@ checksumfs_write(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie, off_t pos,
// special value handled by Write()
}
RETURN_ERROR(node->Write(pos, buffer, *_length, *_length));
// TODO: Modification time update!
bool sizeChanged;
status_t error = node->Write(pos, buffer, *_length, *_length, sizeChanged);
if (error != B_OK)
RETURN_ERROR(error);
// update the modification time and send out a notification from time to
// time
cookie->FileModified(node, sizeChanged);
return B_OK;
}
@ -1384,7 +1484,8 @@ checksumfs_create_dir(fs_volume* fsVolume, fs_vnode* parent, const char* name,
directory->Touched(NODE_MODIFIED);
// commit the transaction
return transaction.Commit();
return transaction.Commit(EntryCreatedNotification(directory, name,
newDirectory));
}