Store the volume watcher in a separate hash table to not collide with

normal nodes.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39107 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler 2010-10-24 00:49:48 +00:00
parent bfff9df5eb
commit d63309cf5e

View File

@ -26,6 +26,8 @@
#include <util/KMessage.h> #include <util/KMessage.h>
#include <util/list.h> #include <util/list.h>
#include "node_monitor_private.h"
//#define TRACE_MONITOR //#define TRACE_MONITOR
#ifdef TRACE_MONITOR #ifdef TRACE_MONITOR
@ -40,9 +42,6 @@
// ToDo: return another error code than B_NO_MEMORY if the team's maximum is hit // ToDo: return another error code than B_NO_MEMORY if the team's maximum is hit
const dev_t kWatchVolumeNode = (dev_t)-1;
typedef struct monitor_listener monitor_listener; typedef struct monitor_listener monitor_listener;
typedef struct node_monitor node_monitor; typedef struct node_monitor node_monitor;
@ -128,11 +127,15 @@ class NodeMonitorService : public NotificationService {
virtual const char* Name() { return "node monitor"; } virtual const char* Name() { return "node monitor"; }
private: private:
void _RemoveMonitor(node_monitor *monitor); void _RemoveMonitor(node_monitor *monitor, uint32 flags);
status_t _RemoveListener(io_context *context, dev_t device, ino_t node,
NotificationListener& notificationListener, bool isVolumeListener);
void _RemoveListener(monitor_listener *listener); void _RemoveListener(monitor_listener *listener);
node_monitor *_MonitorFor(dev_t device, ino_t node); node_monitor *_MonitorFor(dev_t device, ino_t node,
bool isVolumeListener);
status_t _GetMonitor(io_context *context, dev_t device, ino_t node, status_t _GetMonitor(io_context *context, dev_t device, ino_t node,
bool addIfNecessary, node_monitor **_monitor); bool addIfNecessary, node_monitor **_monitor,
bool isVolumeListener);
monitor_listener *_MonitorListenerFor(node_monitor* monitor, monitor_listener *_MonitorListenerFor(node_monitor* monitor,
NotificationListener& notificationListener); NotificationListener& notificationListener);
status_t _AddMonitorListener(io_context *context, status_t _AddMonitorListener(io_context *context,
@ -144,6 +147,9 @@ class NodeMonitorService : public NotificationService {
void _GetInterestedMonitorListeners(dev_t device, ino_t node, void _GetInterestedMonitorListeners(dev_t device, ino_t node,
uint32 flags, interested_monitor_listener_list *interestedListeners, uint32 flags, interested_monitor_listener_list *interestedListeners,
int32 &interestedListenerCount); int32 &interestedListenerCount);
void _GetInterestedVolumeListeners(dev_t device, uint32 flags,
interested_monitor_listener_list *interestedListeners,
int32 &interestedListenerCount);
status_t _SendNotificationMessage(KMessage &message, status_t _SendNotificationMessage(KMessage &message,
interested_monitor_listener_list *interestedListeners, interested_monitor_listener_list *interestedListeners,
int32 interestedListenerCount); int32 interestedListenerCount);
@ -178,7 +184,38 @@ class NodeMonitorService : public NotificationService {
}; };
typedef BOpenHashTable<HashDefinition> MonitorHash; typedef BOpenHashTable<HashDefinition> MonitorHash;
struct volume_hash_key {
dev_t device;
};
struct VolumeHashDefinition {
typedef volume_hash_key* KeyType;
typedef node_monitor ValueType;
size_t HashKey(volume_hash_key* key) const
{ return _Hash(key->device); }
size_t Hash(node_monitor *monitor) const
{ return _Hash(monitor->device); }
bool Compare(volume_hash_key* key, node_monitor *monitor) const
{
return key->device == monitor->device;
}
node_monitor*& GetLink(node_monitor* monitor) const
{ return monitor->hash_link; }
uint32 _Hash(dev_t device) const
{
return (uint32)(device >> 16) + (uint16)device;
}
};
typedef BOpenHashTable<VolumeHashDefinition> VolumeMonitorHash;
MonitorHash fMonitors; MonitorHash fMonitors;
VolumeMonitorHash fVolumeMonitors;
recursive_lock fRecursiveLock; recursive_lock fRecursiveLock;
}; };
@ -251,13 +288,44 @@ NodeMonitorService::InitCheck()
Must be called with monitors lock hold. Must be called with monitors lock hold.
*/ */
void void
NodeMonitorService::_RemoveMonitor(node_monitor *monitor) NodeMonitorService::_RemoveMonitor(node_monitor *monitor, uint32 flags)
{ {
if (flags | B_WATCH_VOLUME)
fVolumeMonitors.Remove(monitor);
else
fMonitors.Remove(monitor); fMonitors.Remove(monitor);
delete monitor; delete monitor;
} }
status_t
NodeMonitorService::_RemoveListener(io_context *context, dev_t device,
ino_t node, NotificationListener& notificationListener,
bool isVolumeListener)
{
TRACE(("%s(dev = %ld, node = %Ld, listener = %p\n",
__PRETTY_FUNCTION__, device, node, &notificationListener));
RecursiveLocker _(fRecursiveLock);
// get the monitor for this device/node pair
node_monitor *monitor = _MonitorFor(device, node, isVolumeListener);
if (monitor == NULL)
return B_BAD_VALUE;
// see if it has the listener we are looking for
monitor_listener* listener = _MonitorListenerFor(monitor,
notificationListener);
if (listener == NULL)
return B_BAD_VALUE;
_RemoveListener(listener);
context->num_monitors--;
return B_OK;
}
/*! Removes the specified monitor_listener from all lists /*! Removes the specified monitor_listener from all lists
and free it. and free it.
Must be called with monitors lock hold. Must be called with monitors lock hold.
@ -265,6 +333,7 @@ NodeMonitorService::_RemoveMonitor(node_monitor *monitor)
void void
NodeMonitorService::_RemoveListener(monitor_listener *listener) NodeMonitorService::_RemoveListener(monitor_listener *listener)
{ {
uint32 flags = listener->flags;
node_monitor *monitor = listener->monitor; node_monitor *monitor = listener->monitor;
// remove it from the listener and I/O context lists // remove it from the listener and I/O context lists
@ -280,7 +349,7 @@ NodeMonitorService::_RemoveListener(monitor_listener *listener)
delete listener; delete listener;
if (monitor->listeners.IsEmpty()) if (monitor->listeners.IsEmpty())
_RemoveMonitor(monitor); _RemoveMonitor(monitor, flags);
} }
@ -288,8 +357,15 @@ NodeMonitorService::_RemoveListener(monitor_listener *listener)
Must be called with monitors lock hold. Must be called with monitors lock hold.
*/ */
node_monitor * node_monitor *
NodeMonitorService::_MonitorFor(dev_t device, ino_t node) NodeMonitorService::_MonitorFor(dev_t device, ino_t node, bool isVolumeListener)
{ {
if (isVolumeListener) {
struct volume_hash_key key;
key.device = device;
return fVolumeMonitors.Lookup(&key);
}
struct monitor_hash_key key; struct monitor_hash_key key;
key.device = device; key.device = device;
key.node = node; key.node = node;
@ -304,9 +380,9 @@ NodeMonitorService::_MonitorFor(dev_t device, ino_t node)
*/ */
status_t status_t
NodeMonitorService::_GetMonitor(io_context *context, dev_t device, ino_t node, NodeMonitorService::_GetMonitor(io_context *context, dev_t device, ino_t node,
bool addIfNecessary, node_monitor** _monitor) bool addIfNecessary, node_monitor** _monitor, bool isVolumeListener)
{ {
node_monitor* monitor = _MonitorFor(device, node); node_monitor* monitor = _MonitorFor(device, node, isVolumeListener);
if (monitor != NULL) { if (monitor != NULL) {
*_monitor = monitor; *_monitor = monitor;
return B_OK; return B_OK;
@ -330,7 +406,12 @@ NodeMonitorService::_GetMonitor(io_context *context, dev_t device, ino_t node,
monitor->device = device; monitor->device = device;
monitor->node = node; monitor->node = node;
if (fMonitors.Insert(monitor) < B_OK) { status_t status;
if (isVolumeListener)
status = fVolumeMonitors.Insert(monitor);
else
status = fMonitors.Insert(monitor);
if (status < B_OK) {
delete monitor; delete monitor;
return B_NO_MEMORY; return B_NO_MEMORY;
} }
@ -369,7 +450,7 @@ NodeMonitorService::_AddMonitorListener(io_context *context,
if (listener == NULL) { if (listener == NULL) {
// no memory for the listener, so remove the monitor as well if needed // no memory for the listener, so remove the monitor as well if needed
if (monitor->listeners.IsEmpty()) if (monitor->listeners.IsEmpty())
_RemoveMonitor(monitor); _RemoveMonitor(monitor, flags);
return B_NO_MEMORY; return B_NO_MEMORY;
} }
@ -397,7 +478,8 @@ NodeMonitorService::AddListener(io_context *context, dev_t device, ino_t node,
RecursiveLocker _(fRecursiveLock); RecursiveLocker _(fRecursiveLock);
node_monitor *monitor; node_monitor *monitor;
status_t status = _GetMonitor(context, device, node, true, &monitor); status_t status = _GetMonitor(context, device, node, true, &monitor,
flags & B_WATCH_VOLUME);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -418,7 +500,8 @@ NodeMonitorService::_UpdateListener(io_context *context, dev_t device,
RecursiveLocker _(fRecursiveLock); RecursiveLocker _(fRecursiveLock);
node_monitor *monitor; node_monitor *monitor;
status_t status = _GetMonitor(context, device, node, false, &monitor); status_t status = _GetMonitor(context, device, node, false, &monitor,
flags | B_WATCH_VOLUME);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -464,7 +547,31 @@ NodeMonitorService::_GetInterestedMonitorListeners(dev_t device, ino_t node,
int32 &interestedListenerCount) int32 &interestedListenerCount)
{ {
// get the monitor for the node // get the monitor for the node
node_monitor *monitor = _MonitorFor(device, node); node_monitor *monitor = _MonitorFor(device, node, false);
if (monitor == NULL)
return;
// iterate through the listeners until we find one with matching flags
MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator();
while (monitor_listener *listener = iterator.Next()) {
if (listener->flags & flags) {
interested_monitor_listener_list &list
= interestedListeners[interestedListenerCount++];
list.iterator = iterator;
list.flags = flags;
return;
}
}
}
void
NodeMonitorService::_GetInterestedVolumeListeners(dev_t device, uint32 flags,
interested_monitor_listener_list *interestedListeners,
int32 &interestedListenerCount)
{
// get the monitor for the node
node_monitor *monitor = _MonitorFor(device, -1, true);
if (monitor == NULL) if (monitor == NULL)
return; return;
@ -546,7 +653,7 @@ NodeMonitorService::NotifyEntryCreatedOrRemoved(int32 opcode, dev_t device,
interested_monitor_listener_list interestedListeners[3]; interested_monitor_listener_list interestedListeners[3];
int32 interestedListenerCount = 0; int32 interestedListenerCount = 0;
// ... for the volume // ... for the volume
_GetInterestedMonitorListeners(device, kWatchVolumeNode, B_WATCH_NAME, _GetInterestedVolumeListeners(device, B_WATCH_NAME,
interestedListeners, interestedListenerCount); interestedListeners, interestedListenerCount);
// ... for the node // ... for the node
if (opcode != B_ENTRY_CREATED) { if (opcode != B_ENTRY_CREATED) {
@ -594,7 +701,7 @@ NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory,
interested_monitor_listener_list interestedListeners[4]; interested_monitor_listener_list interestedListeners[4];
int32 interestedListenerCount = 0; int32 interestedListenerCount = 0;
// ... for the volume // ... for the volume
_GetInterestedMonitorListeners(device, kWatchVolumeNode, B_WATCH_NAME, _GetInterestedVolumeListeners(device, B_WATCH_NAME,
interestedListeners, interestedListenerCount); interestedListeners, interestedListenerCount);
// ... for the node // ... for the node
_GetInterestedMonitorListeners(nodeDevice, node, B_WATCH_NAME, _GetInterestedMonitorListeners(nodeDevice, node, B_WATCH_NAME,
@ -639,7 +746,7 @@ NodeMonitorService::NotifyStatChanged(dev_t device, ino_t node,
interested_monitor_listener_list interestedListeners[3]; interested_monitor_listener_list interestedListeners[3];
int32 interestedListenerCount = 0; int32 interestedListenerCount = 0;
// ... for the volume // ... for the volume
_GetInterestedMonitorListeners(device, kWatchVolumeNode, B_WATCH_STAT, _GetInterestedVolumeListeners(device, B_WATCH_STAT,
interestedListeners, interestedListenerCount); interestedListeners, interestedListenerCount);
// ... for the node, depending on wether its an interim update or not // ... for the node, depending on wether its an interim update or not
_GetInterestedMonitorListeners(device, node, _GetInterestedMonitorListeners(device, node,
@ -687,7 +794,7 @@ NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t node,
interested_monitor_listener_list interestedListeners[3]; interested_monitor_listener_list interestedListeners[3];
int32 interestedListenerCount = 0; int32 interestedListenerCount = 0;
// ... for the volume // ... for the volume
_GetInterestedMonitorListeners(device, kWatchVolumeNode, B_WATCH_ATTR, _GetInterestedVolumeListeners(device, B_WATCH_ATTR,
interestedListeners, interestedListenerCount); interestedListeners, interestedListenerCount);
// ... for the node // ... for the node
_GetInterestedMonitorListeners(device, node, B_WATCH_ATTR, _GetInterestedMonitorListeners(device, node, B_WATCH_ATTR,
@ -850,21 +957,11 @@ NodeMonitorService::RemoveListener(io_context *context, dev_t device,
RecursiveLocker _(fRecursiveLock); RecursiveLocker _(fRecursiveLock);
// get the monitor for this device/node pair if (_RemoveListener(context, device, node, notificationListener, false)
node_monitor *monitor = _MonitorFor(device, node); == B_OK)
if (monitor == NULL)
return B_BAD_VALUE;
// see if it has the listener we are looking for
monitor_listener* listener = _MonitorListenerFor(monitor,
notificationListener);
if (listener == NULL)
return B_BAD_VALUE;
_RemoveListener(listener);
context->num_monitors--;
return B_OK; return B_OK;
return _RemoveListener(context, device, node, notificationListener, true);
} }
@ -908,7 +1005,8 @@ NodeMonitorService::UpdateUserListener(io_context *context, dev_t device,
RecursiveLocker _(fRecursiveLock); RecursiveLocker _(fRecursiveLock);
node_monitor *monitor; node_monitor *monitor;
status_t status = _GetMonitor(context, device, node, true, &monitor); status_t status = _GetMonitor(context, device, node, true, &monitor,
flags | B_WATCH_VOLUME);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -924,7 +1022,7 @@ NodeMonitorService::UpdateUserListener(io_context *context, dev_t device,
userListener); userListener);
if (copiedListener == NULL) { if (copiedListener == NULL) {
if (monitor->listeners.IsEmpty()) if (monitor->listeners.IsEmpty())
_RemoveMonitor(monitor); _RemoveMonitor(monitor, flags);
return B_NO_MEMORY; return B_NO_MEMORY;
} }