Here's a preliminary patch that adds a FAMAccessed event to allow clients
to be notified about file reads. I'd very much like to see something like
this rolled into the mainstream FAM, so if anybody has any suggestions for
changes that'll let that happen, I'd love to hear about it.
Thanks,
Nathan
diff -burp fam-oss-2.6.4/fam/DNotify.c++ fam-oss-2.6.4-ndt/fam/DNotify.c++
--- fam-oss-2.6.4/fam/DNotify.c++ Tue Nov 6 17:21:26 2001
+++ fam-oss-2.6.4-ndt/fam/DNotify.c++ Wed Nov 7 10:09:08 2001
@@ -340,7 +340,8 @@ DNotify::watch_dir(const char *notify_di
dwatch->fd = open(notify_dir, O_RDONLY);
fcntl (dwatch->fd, F_SETSIG, SIGRTMIN);
fcntl (dwatch->fd, F_NOTIFY,
- (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) |
DN_MULTISHOT);
+ (DN_MODIFY|DN_CREATE|DN_DELETE|
+ DN_RENAME|DN_ATTRIB|DN_ACCESS) | DN_MULTISHOT);
hash_dirwatch (dwatch);
}
diff -burp fam-oss-2.6.4/fam/Event.c++ fam-oss-2.6.4-ndt/fam/Event.c++
--- fam-oss-2.6.4/fam/Event.c++ Sat May 20 00:46:31 2000
+++ fam-oss-2.6.4-ndt/fam/Event.c++ Wed Nov 7 10:47:05 2001
@@ -32,6 +32,7 @@ const Event Event::Deleted = Event(D
const Event Event::Executing = Event(ExecutingT);
const Event Event::Exited = Event(ExitedT);
const Event Event::Created = Event(CreatedT);
+const Event Event::Accessed = Event(AccessedT);
const Event Event::Acknowledge = Event(AcknowledgeT);
const Event Event::Exists = Event(ExistsT);
const Event Event::EndExist = Event(EndExistT);
@@ -55,6 +56,8 @@ Event::getEventFromOpcode(char opcode)
return &Created;
// case 'M': /* M is unsupported */
// return Moved;
+ case 's':
+ return &Accessed;
case 'G':
return &Acknowledge;
case 'e':
@@ -90,6 +93,9 @@ Event::name() const
case CreatedT:
return "Created";
+ case AccessedT:
+ return "Accessed";
+
case MovedT:
return "Moved";
@@ -113,7 +119,7 @@ Event::code() const
{
// Map event to letter.
- static const char codeletters[] = "?cAXQFMGeP";
+ static const char codeletters[] = "?cAXQFMsGeP";
assert(which < sizeof codeletters - 1);
char code = codeletters[which];
assert(code != '?');
diff -burp fam-oss-2.6.4/fam/Event.h fam-oss-2.6.4-ndt/fam/Event.h
--- fam-oss-2.6.4/fam/Event.h Sat May 20 00:46:31 2000
+++ fam-oss-2.6.4-ndt/fam/Event.h Wed Nov 7 15:57:46 2001
@@ -47,6 +47,7 @@ public:
static const Event Created;
// Moved is not supported
// static const Event Moved;
+ static const Event Accessed;
static const Event Acknowledge;
static const Event Exists;
static const Event EndExist;
@@ -60,6 +61,7 @@ private:
ExitedT = FAMStopExecuting, // 'Q'
CreatedT = FAMCreated, // 'F'
MovedT = FAMMoved, // 'M' (Not supported)
+ AccessedT = FAMAccessed, // 's'
AcknowledgeT = FAMAcknowledge, // 'G'
ExistsT = FAMExists, // 'e'
EndExistT = FAMEndExist, // 'P'
diff -burp fam-oss-2.6.4/fam/Interest.c++ fam-oss-2.6.4-ndt/fam/Interest.c++
--- fam-oss-2.6.4/fam/Interest.c++ Tue Nov 6 17:21:49 2001
+++ fam-oss-2.6.4-ndt/fam/Interest.c++ Mon Nov 12 14:18:59 2001
@@ -162,7 +162,53 @@ Interest::dev_ino(dev_t newdev, ino_t ne
hashlink = NULL;
}
-/* Returns true if file changed since last stat */
+/* Returns true if the file has been "accessed" -- ie., "read from" --
+ since the last stat, *AND* if the file has not been changed
+ since the last stat. Calling this routine does not count as a call to
+ do_stat(), nor does it count as an "access".
+*/
+bool
+Interest::accessed_since_stat()
+{
+ // Consider the case of a Directory changing into a file to be a
+ // simple change, and send only a Changed event.
+
+ struct stat status;
+ int rc = lstat(name(), &status);
+ if (rc < 0) {
+ if (errno == ETIMEDOUT) {
+ return false;
+ }
+ memset(&status, 0, sizeof status);
+ }
+
+ bool exists = status.st_mode != 0;
+ bool did_exist = old_stat.st_mode != 0;
+ bool access_happened = (old_stat.st_atime != status.st_atime);
+
+ if (exists && !did_exist)
+ {
+ post_event(Event::Created);
+ notify_created(this);
+ }
+ else if (did_exist && !exists)
+ {
+ post_event(Event::Deleted);
+ notify_deleted(this);
+ }
+
+ // If dev/ino changed, move this interest to the right hash chain.
+ if (status.st_dev != dev || status.st_ino != ino) {
+ dev_ino(status.st_dev, status.st_ino);
+ }
+ return access_happened;
+}
+
+
+/* Returns true if file changed since last stat. This function
+ MUST NOT change the access time on the file, or the FAMAccessed
+ event won't work correctly.
+ */
bool
Interest::do_stat()
{
@@ -215,12 +261,17 @@ bool
Interest::do_scan()
{
bool stat_changed = false;
+ bool accessed = false;
if (needs_scan() && active())
{ needs_scan(false);
bool did_exist = exists();
+
+ accessed = accessed_since_stat();
stat_changed = do_stat();
if (stat_changed && did_exist && exists())
post_event(Event::Changed);
+ else if (accessed && did_exist && exists())
+ post_event(Event::Accessed);
report_exec_state();
}
return stat_changed;
diff -burp fam-oss-2.6.4/fam/Interest.h fam-oss-2.6.4-ndt/fam/Interest.h
--- fam-oss-2.6.4/fam/Interest.h Tue Nov 6 17:21:26 2001
+++ fam-oss-2.6.4-ndt/fam/Interest.h Fri Nov 9 14:32:55 2001
@@ -59,7 +59,12 @@ public:
virtual ~Interest();
const char *name() const { return myname; }
+
+ /* This function MUST NOT change the file's access time, or
+ the FAMAccessed event won't work correctly.
+ */
bool exists() const { return old_stat.st_mode != 0; }
+
bool isdir() const { return (old_stat.st_mode & S_IFMT) == S_IFDIR; }
virtual bool active() const = 0;
bool needs_scan() const { return scan_state != OK; }
@@ -80,6 +85,7 @@ public:
protected:
+ bool accessed_since_stat();
bool do_stat();
virtual void post_event(const Event&, const char * = NULL) = 0;
char& ci_bits() { return ci_char; }
diff -burp fam-oss-2.6.4/fam/InternalClient.c++
fam-oss-2.6.4-ndt/fam/InternalClient.c++
--- fam-oss-2.6.4/fam/InternalClient.c++ Sat May 20 00:46:31 2000
+++ fam-oss-2.6.4-ndt/fam/InternalClient.c++ Mon Nov 12 14:19:42 2001
@@ -70,7 +70,7 @@ InternalClient::enqueue_scanner(Scanner
}
void
-InternalClient::post_event(const Event& event, Request, const char *)
+InternalClient::post_event(const Event& event, Request, const char *name)
{
// Log::debug("sent %s event: \"%s\" %s", Client::name(), name, event.name());
(*handler)(event, closure);
diff -burp fam-oss-2.6.4/fam/InternalClient.h
fam-oss-2.6.4-ndt/fam/InternalClient.h
--- fam-oss-2.6.4/fam/InternalClient.h Sat May 20 00:46:31 2000
+++ fam-oss-2.6.4-ndt/fam/InternalClient.h Fri Nov 9 14:02:32 2001
@@ -43,7 +43,7 @@ public:
~InternalClient();
bool ready_for_events();
- void post_event(const Event&, Request, const char *name);
+ void post_event(const Event& event, Request, const char *name);
void enqueue_for_scan(Interest *);
void dequeue_from_scan(Interest *);
void enqueue_scanner(Scanner *);
diff -burp fam-oss-2.6.4/fam/NetConnection.c++
fam-oss-2.6.4-ndt/fam/NetConnection.c++
--- fam-oss-2.6.4/fam/NetConnection.c++ Sat May 20 00:46:31 2000
+++ fam-oss-2.6.4-ndt/fam/NetConnection.c++ Mon Nov 12 14:21:29 2001
@@ -126,14 +126,17 @@ NetConnection::input()
int maxbytes = iend - itail;
int ret = recv(fd, itail, maxbytes, 0);
if (ret < 0)
- { if (errno != EAGAIN && errno != ECONNRESET)
+ {
+ if (errno != EAGAIN && errno != ECONNRESET)
{ Log::perror("fd %d read error", fd);
shutdown();
}
return;
}
else if (ret == 0)
- { shutdown();
+ {
+ Log::debug("input: recv() call came back empty, shutting down");
+ shutdown();
return;
}
else // (ret > 0)
diff -burp fam-oss-2.6.4/fam/ServerHost.c++ fam-oss-2.6.4-ndt/fam/ServerHost.c++
--- fam-oss-2.6.4/fam/ServerHost.c++ Sat May 20 00:46:32 2000
+++ fam-oss-2.6.4-ndt/fam/ServerHost.c++ Mon Nov 12 14:22:36 2001
@@ -186,8 +186,8 @@ ServerHost::disconnect_handler(void *clo
// necessary because NFS caches attribute information and we have to
// wait for old cached info to be out of date.
//
-// For "Changed" events, we save the path because we need it to look
-// up a DirEntry. We don't save the result of the first lookup
+// For "Changed" and "Accessed" events, we save the path because we need
+// it to look up a DirEntry. We don't save the result of the first lookup
// because result may become invalid while we're sleeping.
//
// There is no way to avoid the deferred scan short of adding a
@@ -205,15 +205,18 @@ ServerHost::event_handler(const Event* e
// Also enqueue a deferred task to rescan later.
if (*event == Event::Changed || *event == Event::Deleted ||
- *event == Event::Created || *event == Event::Exists)
+ *event == Event::Created || *event == Event::Exists ||
+ *event == Event::Accessed)
{
ClientInterest *cip = host->requests.find(r);
if (!cip)
return;
Interest *ip;
- if (*event == Event::Changed || *event == Event::Deleted)
- { ip = cip->find_name(path);
+ if (*event == Event::Accessed || *event == Event::Changed ||
+ *event == Event::Deleted)
+ {
+ ip = cip->find_name(path);
if (!ip)
return;
}
diff -burp fam-oss-2.6.4/fam/TCP_Client.c++ fam-oss-2.6.4-ndt/fam/TCP_Client.c++
--- fam-oss-2.6.4/fam/TCP_Client.c++ Sat May 20 00:46:32 2000
+++ fam-oss-2.6.4-ndt/fam/TCP_Client.c++ Wed Nov 7 15:46:26 2001
@@ -310,7 +310,7 @@ void
TCP_Client::post_event(const Event& event, Request request, const char *path)
{
conn.send_event(event, request, path);
- Log::debug("sent event to %s: request %d \"%s\" %s",
+ Log::debug("TCP_Client sent event to %s: request %d \"%s\" %s",
name(), request, path, event.name());
}
diff -burp fam-oss-2.6.4/include/fam.h fam-oss-2.6.4-ndt/include/fam.h
--- fam-oss-2.6.4/include/fam.h Sat May 20 00:46:32 2000
+++ fam-oss-2.6.4-ndt/include/fam.h Wed Nov 7 09:36:41 2001
@@ -114,7 +114,8 @@ typedef struct FAMRequest {
*****************************************************************************/
enum FAMCodes { FAMChanged=1, FAMDeleted=2, FAMStartExecuting=3,
FAMStopExecuting=4, FAMCreated=5, FAMMoved=6,
- FAMAcknowledge=7, FAMExists=8, FAMEndExist=9 };
+ FAMAccessed=7, FAMAcknowledge=8, FAMExists=9,
+ FAMEndExist=10 };
typedef struct FAMEvent {
FAMConnection* fc; /* The fam connection that event occurred on */
diff -burp fam-oss-2.6.4/libfam/Client.c++ fam-oss-2.6.4-ndt/libfam/Client.c++
--- fam-oss-2.6.4/libfam/Client.c++ Sat May 20 00:46:32 2000
+++ fam-oss-2.6.4-ndt/libfam/Client.c++ Mon Nov 12 14:23:42 2001
@@ -224,7 +224,10 @@ Client::eventPending()
int
Client::nextEvent(FAMEvent *fe)
{
- if (!connected()) return -1;
+ if (!connected())
+ {
+ return -1;
+ }
if ((!haveCompleteEvent) && (readEvent(true) < 0))
{
// EOF now
@@ -284,6 +287,9 @@ Client::nextEvent(FAMEvent *fe)
*q = '\0';
switch (code) {
+ case 's': // access
+ fe->code = FAMAccessed;
+ break;
case 'c': // change
fe->code = FAMChanged;
break;
@@ -318,7 +324,7 @@ Client::nextEvent(FAMEvent *fe)
return -1;
}
#ifdef DEBUG
-printf("\nFAM received %s ", msg);
+printf("\nFAM received %c ", code);
printf("translated to event code:%d, reqnum:%d, ud:%d, filename:<%s>\n",
fe->code, reqnum, fe->userdata, fe->filename);
#endif
|