[vhffs-dev] [1540] fixed a design bug about paths, we used to keep full pathname in memory, which is very hard to deal when directories are moved to parents dirs, now are now building a very simple tree with lookup through a hash table |
[ Thread Index |
Date Index
| More vhffs.org/vhffs-dev Archives
]
- To: vhffs-dev@xxxxxxxxx
- Subject: [vhffs-dev] [1540] fixed a design bug about paths, we used to keep full pathname in memory, which is very hard to deal when directories are moved to parents dirs, now are now building a very simple tree with lookup through a hash table
- From: subversion@xxxxxxxxxxxxx
- Date: Tue, 19 Jan 2010 01:41:00 +0100
Revision: 1540
Author: gradator
Date: 2010-01-19 01:41:00 +0100 (Tue, 19 Jan 2010)
Log Message:
-----------
fixed a design bug about paths, we used to keep full pathname in memory, which is very hard to deal when directories are moved to parents dirs, now are now building a very simple tree with lookup through a hash table
Modified Paths:
--------------
trunk/vhffs-fssync/vhffsfssync_master.c
Modified: trunk/vhffs-fssync/vhffsfssync_master.c
===================================================================
--- trunk/vhffs-fssync/vhffsfssync_master.c 2010-01-13 01:18:47 UTC (rev 1539)
+++ trunk/vhffs-fssync/vhffsfssync_master.c 2010-01-19 00:41:00 UTC (rev 1540)
@@ -26,7 +26,9 @@
#define DEBUG_NET 0
#define DEBUG_INOTIFY 0
#define DEBUG_EVENTS 0
+//#define NDEBUG
+#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -58,11 +60,17 @@
// Will never be used: IN_ACCESS, IN_OPEN, IN_CLOSE_NOWRITE
// each monitor entry is associated with a path, we need to keep it to compute the path
-//char **vhffsfssync_wd_to_path = NULL;
-//int vhffsfssync_wd_to_path_len = 0; // number of allocated paths
-GHashTable *vhffsfssync_wd_to_path;
-GHashTable *vhffsfssync_path_to_wd;
+//char **vhffsfssync_wd_to_watch = NULL;
+//int vhffsfssync_wd_to_watch_len = 0; // number of allocated paths
+GHashTable *vhffsfssync_wd_to_watch;
+
+typedef struct vhffsfssync_watch_ {
+ int wd;
+ char *dirname;
+ struct vhffsfssync_watch_ *parent;
+} vhffsfssync_watch;
+
// return a timestamp in ms (it loops for 100000 sec)
/*inline int vhffsfssync_timestamp() {
struct timeval tv;
@@ -72,20 +80,21 @@
struct vhffsfssync_cookie {
uint32_t id;
- char *from;
+ vhffsfssync_watch *watch;
+ char *filename;
gboolean isdir;
};
static struct vhffsfssync_cookie vhffsfssync_cookie;
// protos
-int vhffsfssync_add_watch(int inotifyfd, const char *pathname, uint32_t mask);
-int vhffsfssync_modify_watch(int inotifyfd, const char *from, const char *to);
-int vhffsfssync_del_watch(int inotifyfd, const char *pathname, int wd);
-int vhffsfssync_add_watch_recursively(int inotifyfd, const char *pathname, uint32_t mask);
-int vhffsfssync_manage_event_remove(int inotifyfd, char *pathname);
-int vhffsfssync_manage_event_create(int inotifyfd, char *pathname);
+char *vhffsfssync_pathname(vhffsfssync_watch *watch, const char *filename);
+vhffsfssync_watch *vhffsfssync_add_watch(int inotifyfd, vhffsfssync_watch *parent, const char *dirname, uint32_t mask);
+int vhffsfssync_del_watch(int inotifyfd, vhffsfssync_watch *watch);
+vhffsfssync_watch *vhffsfssync_add_watch_recursively(int inotifyfd, vhffsfssync_watch *parent, const char *dirname, uint32_t mask);
+int vhffsfssync_manage_event_remove(int inotifyfd, vhffsfssync_watch *watch, char *filename);
+int vhffsfssync_manage_event_create(int inotifyfd, vhffsfssync_watch *watch, char *filename);
int vhffsfssync_manage_event(int inotifyfd, struct inotify_event *event);
-int vhffsfssync_fake_events_recursively(int inotifyfd, char *pathname);
+int vhffsfssync_fake_events_recursively(int inotifyfd, vhffsfssync_watch *watch);
/* -- network stuff -- */
@@ -568,6 +577,7 @@
}
+// TODO: improve that, using *watch is probably faster
char *vhffsfssync_net_parent_mtime(char *pathname) {
char *cur;
struct stat st;
@@ -1190,128 +1200,134 @@
/* -- inotify stuff -- */
-int vhffsfssync_add_watch(int inotifyfd, const char *pathname, uint32_t mask) {
+char *vhffsfssync_pathname(vhffsfssync_watch *watch, const char *filename) {
+
+ GString *pathname = g_string_sized_new(256);
- int wd;
- int *_wd;
- char *_pathname;
+ // TODO: improve that, prepend is probably slow
+ while(watch) {
+ g_string_prepend_c(pathname, '/');
+ g_string_prepend(pathname, watch->dirname);
+ watch = watch->parent;
+ }
- if( g_hash_table_lookup(vhffsfssync_path_to_wd, pathname) ) {
- return -1;
+ if(filename) {
+ g_string_append(pathname, filename);
}
+// if(watch) printf("=d> %s\n", watch->dirname);
+// if(filename) printf("=f> %s\n", filename);
+// printf("==> %s\n", pathname->str);
+ return g_string_free(pathname, FALSE);
+}
+
+
+vhffsfssync_watch *vhffsfssync_add_watch(int inotifyfd, vhffsfssync_watch *parent, const char *dirname, uint32_t mask) {
+
+ int wd;
+ char *pathname;
+ vhffsfssync_watch *watch;
+
+ pathname = vhffsfssync_pathname(parent, dirname);
+#if DEBUG_INOTIFY
+ printf("t+ %s\n", pathname);
+#endif
+
wd = inotify_add_watch(inotifyfd, pathname, mask);
if(wd < 0) {
if(errno == ENOSPC) {
fprintf(stderr, "Maximum number of watches reached, consider adding more...\n");
}
- return wd;
+ free(pathname);
+ return NULL;
}
+
+ if( (watch = g_hash_table_lookup(vhffsfssync_wd_to_watch, &wd)) ) {
- _wd = g_new(int, 1);
- *_wd = wd;
- _pathname = g_strdup(pathname);
- g_hash_table_insert(vhffsfssync_wd_to_path, _wd, _pathname);
- g_hash_table_insert(vhffsfssync_path_to_wd, _pathname, _wd);
+ // this was already watched, update name and reattach to the new parent
+ free(watch->dirname);
+ watch->dirname = g_strdup(dirname);
+ watch->parent = parent;
-// if(wd >= vhffsfssync_wd_to_path_len) {
-// vhffsfssync_wd_to_path_len = ( (wd >>10) +1) <<10;
-// vhffsfssync_wd_to_path = realloc( vhffsfssync_wd_to_path, vhffsfssync_wd_to_path_len * sizeof(void*) );
-// }
-// vhffsfssync_wd_to_path[wd] = strdup(pathname);
#if DEBUG_INOTIFY
- printf("+ %d %s\n", wd, pathname);
+ printf("u+ %d %s\n", wd, pathname);
#endif
- return wd;
-}
+ free(pathname);
+ return watch;
+ }
+ watch = malloc(sizeof(vhffsfssync_watch));
+ watch->wd = wd;
+ watch->dirname = g_strdup(dirname);
+ watch->parent = parent;
-int vhffsfssync_del_watch(int inotifyfd, const char *pathname, int wd) {
+// _wd = g_new(int, 1);
+// *_wd = wd;
+ g_hash_table_insert(vhffsfssync_wd_to_watch, &watch->wd, watch);
- if(!pathname && wd > 0) {
- pathname = (char*)g_hash_table_lookup(vhffsfssync_wd_to_path, &wd);
- // this wd has already been deleted
- if(!pathname) return -1;
- }
- else if(pathname && wd == 0) {
- int *_wd;
- _wd = g_hash_table_lookup(vhffsfssync_path_to_wd, pathname);
- // this wd has already been deleted
- if(!_wd) return -1;
- wd = *_wd;
- }
- else return -1;
+// if(wd >= vhffsfssync_wd_to_watch_len) {
+// vhffsfssync_wd_to_watch_len = ( (wd >>10) +1) <<10;
+// vhffsfssync_wd_to_watch = realloc( vhffsfssync_wd_to_watch, vhffsfssync_wd_to_watch_len * sizeof(void*) );
+// }
+// vhffsfssync_wd_to_watch[wd] = strdup(pathname);
#if DEBUG_INOTIFY
- printf("- %d %s\n", wd, pathname);
+ printf("a+ %d %s\n", wd, pathname);
#endif
- g_hash_table_remove(vhffsfssync_path_to_wd, pathname);
- g_hash_table_remove(vhffsfssync_wd_to_path, &wd);
- return inotify_rm_watch(inotifyfd, wd);
+ free(pathname);
+ return watch;
}
-int vhffsfssync_modify_watch(int inotifyfd, const char *from, const char *to) {
+int vhffsfssync_del_watch(int inotifyfd, vhffsfssync_watch *watch) {
- int wd;
- int *_wd;
- char *_to;
-
- _wd = g_hash_table_lookup(vhffsfssync_path_to_wd, from);
- if(!_wd) return -1;
- wd = *_wd;
-
- g_hash_table_remove(vhffsfssync_path_to_wd, from);
- g_hash_table_remove(vhffsfssync_wd_to_path, _wd);
-
- _wd = g_new(int, 1);
- *_wd = wd;
- _to = strdup(to);
- g_hash_table_insert(vhffsfssync_wd_to_path, _wd, _to);
- g_hash_table_insert(vhffsfssync_path_to_wd, _to, _wd);
-
#if DEBUG_INOTIFY
- printf("= %d %s -> %s\n", wd, from, to);
+ char *pathname = vhffsfssync_pathname(watch, NULL);
+ printf("- %d %s\n", watch->wd, pathname);
+ free(pathname);
#endif
+ g_hash_table_remove(vhffsfssync_wd_to_watch, &watch->wd);
+ inotify_rm_watch(inotifyfd, watch->wd);
+ free(watch->dirname);
+ free(watch);
return 0;
}
-int vhffsfssync_add_watch_recursively(int inotifyfd, const char *pathname, uint32_t mask) {
+vhffsfssync_watch *vhffsfssync_add_watch_recursively(int inotifyfd, vhffsfssync_watch *parent, const char *dirname, uint32_t mask) {
- int wd;
+ vhffsfssync_watch *watch;
+ char *pathname;
DIR *d;
- wd = vhffsfssync_add_watch(inotifyfd, pathname, mask);
- if(wd < 0) return wd;
+ watch = vhffsfssync_add_watch(inotifyfd, parent, dirname, mask);
+ if(!watch) return NULL;
+ pathname = vhffsfssync_pathname(parent, dirname);
d = opendir(pathname);
+ free(pathname);
if(d) {
struct dirent *dir;
while( (dir = readdir(d)) ) {
if(dir->d_type == DT_DIR && strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") ) {
- char *path;
- path = g_strdup_printf("%s/%s", pathname, dir->d_name);
- wd = vhffsfssync_add_watch_recursively(inotifyfd, path, mask);
- free(path);
+ vhffsfssync_add_watch_recursively(inotifyfd, watch, dir->d_name, mask);
}
}
closedir(d);
}
- return wd;
+ return watch;
}
-int vhffsfssync_manage_event_remove(int inotifyfd, char *pathname) {
+int vhffsfssync_manage_event_remove(int inotifyfd, vhffsfssync_watch *watch, char *filename) {
+ char *pathname;
GList *conns;
- int *_wd;
+ pathname = vhffsfssync_pathname(watch, filename);
+
#if DEBUG_INOTIFY
printf("==> REMOVE %s\n", pathname);
#endif
- if( (_wd = g_hash_table_lookup(vhffsfssync_path_to_wd, pathname)) ) {
- vhffsfssync_del_watch(inotifyfd, NULL, *_wd);
- }
/* connections */
for(conns = g_list_first(vhffsfssync_conns) ; conns ; ) {
@@ -1321,13 +1337,18 @@
vhffsfssync_net_send_event(conn, g_strdup_printf("remove%c%s%c", '\0', pathname, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
vhffsfssync_net_send_event(conn, vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
}
+
+ free(pathname);
return 0;
}
-int vhffsfssync_manage_event_create(int inotifyfd, char *pathname) {
+int vhffsfssync_manage_event_create(int inotifyfd, vhffsfssync_watch *watch, char *filename) {
struct stat st;
+ char *pathname;
+ pathname = vhffsfssync_pathname(watch, filename);
+
if(! lstat(pathname, &st) ) {
if( S_ISREG(st.st_mode) ) {
@@ -1344,15 +1365,16 @@
}
else if( S_ISDIR(st.st_mode) ) {
+ vhffsfssync_watch *newwatch;
#if DEBUG_INOTIFY
printf("==> MKDIR %s\n", pathname);
#endif
- vhffsfssync_add_watch(inotifyfd, pathname, VHFFSFSSYNC_WATCH_MASK);
+ newwatch = vhffsfssync_add_watch(inotifyfd, watch, filename, VHFFSFSSYNC_WATCH_MASK);
vhffsfssync_net_broadcast_event( g_strdup_printf("mkdir%c%s%c%ld%c", '\0', pathname, '\0', st.st_mtime, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
/* there is a short delay between the mkdir() and the add_watch(),
we need to send events about the data which have already been written */
- vhffsfssync_fake_events_recursively( inotifyfd, pathname );
+ vhffsfssync_fake_events_recursively( inotifyfd, newwatch );
}
else if( S_ISLNK(st.st_mode) ) {
@@ -1374,6 +1396,7 @@
// file already disappeared (common for temporary files)
} else {
fprintf(stderr, "cannot readlink() '%s': %s\n", pathname, strerror(errno));
+ free(pathname);
return -1;
}
}
@@ -1386,17 +1409,20 @@
// file already disappeared (common for temporary files)
} else {
fprintf(stderr, "cannot lstat() '%s': %s\n", pathname, strerror(errno));
+ free(pathname);
return -1;
}
}
+ free(pathname);
return 0;
}
int vhffsfssync_manage_event(int inotifyfd, struct inotify_event *event) {
- char *dirpath, *pathname;
+ vhffsfssync_watch *watch;
+ char *pathname;
#if DEBUG_INOTIFY
printf("wd=%d mask=%x cookie=%d len=%d", event->wd, event->mask, event->cookie, event->len);
if(event->len > 0) printf(" name=%s", event->name);
@@ -1408,22 +1434,21 @@
return -1;
}
- dirpath = (char*)g_hash_table_lookup(vhffsfssync_wd_to_path, &event->wd);
- // this wd has been deleted
- if(!dirpath) return -1;
+ watch = g_hash_table_lookup(vhffsfssync_wd_to_watch, &event->wd);
+ assert( watch != NULL );
if(event->len > 0) {
- pathname = g_strdup_printf("%s/%s", dirpath, event->name);
+ pathname = vhffsfssync_pathname(watch, event->name);
} else {
- pathname = strdup(dirpath);
+ pathname = vhffsfssync_pathname(watch, NULL);
}
// this event is not waiting for a cookie, delete file if necessary (IN_MOVED_FROM not followed with IN_MOVED_TO)
if( !(event->mask & IN_MOVED_TO) && vhffsfssync_cookie.id ) {
- vhffsfssync_manage_event_remove(inotifyfd, vhffsfssync_cookie.from);
+ vhffsfssync_manage_event_remove(inotifyfd, vhffsfssync_cookie.watch, vhffsfssync_cookie.filename);
vhffsfssync_cookie.id = 0;
- free(vhffsfssync_cookie.from);
+ free(vhffsfssync_cookie.filename);
}
// new mtime (and also atime, chmod and chown, but we are not using them)
@@ -1448,14 +1473,14 @@
#if DEBUG_INOTIFY
printf("IN_CREATE\n");
#endif
- vhffsfssync_manage_event_create(inotifyfd, pathname);
+ vhffsfssync_manage_event_create(inotifyfd, watch, event->name);
// deleted file, directory or symlink
} else if( event->mask & IN_DELETE ) {
#if DEBUG_INOTIFY
printf("IN_DELETE\n");
#endif
- vhffsfssync_manage_event_remove(inotifyfd, pathname);
+ vhffsfssync_manage_event_remove(inotifyfd, watch, event->name);
// watch deleted, not used
} else if( event->mask & IN_DELETE_SELF ) {
@@ -1466,15 +1491,15 @@
// event was added, in this case the add_watch failed to monitor this dir
// and we'll not receive a IN_DELETE_SELF for it
//
- //implicit deletion (IN_IGNORED will follow this event)
- //vhffsfssync_del_watch(inotifyfd, event->wd);
+ // Anyway, a IN_IGNORE event will be sent, IN_DELETE_SELF is only
+ // useful for monitored files, that is not used here.
// file modified
} else if( event->mask & IN_MODIFY ) {
#if DEBUG_INOTIFY
printf("IN_MODIFY\n");
/* we can send the data here */
- printf("==> SEND %s\n", pathname);
+// printf("==> SEND %s\n", pathname);
#endif
// file modified and closed
} else if( event->mask & IN_CLOSE_WRITE ) {
@@ -1504,7 +1529,8 @@
#endif
// set the cookie
vhffsfssync_cookie.id = event->cookie;
- vhffsfssync_cookie.from = strdup(pathname);
+ vhffsfssync_cookie.watch = watch;
+ vhffsfssync_cookie.filename = strdup(event->name);
vhffsfssync_cookie.isdir = !!( event->mask & IN_ISDIR );
} else if( event->mask & IN_MOVED_TO ) {
@@ -1514,25 +1540,30 @@
// mv
if(vhffsfssync_cookie.id == event->cookie) {
#if DEBUG_INOTIFY
- printf("==> MOVE %s -> %s (used cookie %d)\n", vhffsfssync_cookie.from, pathname, vhffsfssync_cookie.id);
+ char *tmp = vhffsfssync_pathname(vhffsfssync_cookie.watch, vhffsfssync_cookie.filename);
+ printf("==> MOVE (%d -> %d) %s -> %s (used cookie %d)\n", vhffsfssync_cookie.watch->wd, watch->wd, tmp, pathname, vhffsfssync_cookie.id);
+ free(tmp);
#endif
if( vhffsfssync_cookie.isdir ) {
- vhffsfssync_modify_watch(inotifyfd, vhffsfssync_cookie.from, pathname);
- vhffsfssync_net_broadcast_event( g_strdup_printf("move%c%s%c%s%c", '\0', vhffsfssync_cookie.from, '\0', pathname, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
- vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(vhffsfssync_cookie.from) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+
+ char *frompathname = vhffsfssync_pathname(vhffsfssync_cookie.watch, vhffsfssync_cookie.filename);
+ vhffsfssync_add_watch(inotifyfd, watch, event->name, VHFFSFSSYNC_WATCH_MASK);
+ vhffsfssync_net_broadcast_event( g_strdup_printf("move%c%s%c%s%c", '\0', frompathname, '\0', pathname, '\0') , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+ vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(frompathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
vhffsfssync_net_broadcast_event( vhffsfssync_net_parent_mtime(pathname) , VHFFSFSSYNC_NET_PRIO_MEDIUM);
+ free(frompathname);
}
else {
- vhffsfssync_manage_event_remove(inotifyfd, vhffsfssync_cookie.from);
- vhffsfssync_manage_event_create(inotifyfd, pathname);
+ vhffsfssync_manage_event_remove(inotifyfd, vhffsfssync_cookie.watch, vhffsfssync_cookie.filename);
+ vhffsfssync_manage_event_create(inotifyfd, watch, event->name);
}
vhffsfssync_cookie.id = 0;
- free(vhffsfssync_cookie.from);
+ free(vhffsfssync_cookie.filename);
}
// create
else {
- vhffsfssync_manage_event_create(inotifyfd, pathname);
+ vhffsfssync_manage_event_create(inotifyfd, watch, event->name);
}
// watch deleted, clean it
@@ -1540,7 +1571,7 @@
#if DEBUG_INOTIFY
printf("IN_IGNORED\n");
#endif
- vhffsfssync_del_watch(inotifyfd, NULL, event->wd);
+ vhffsfssync_del_watch(inotifyfd, watch);
// this event is not handled, this should not happen
} else {
@@ -1554,21 +1585,21 @@
}
-int vhffsfssync_fake_events_recursively(int inotifyfd, char *pathname) {
+int vhffsfssync_fake_events_recursively(int inotifyfd, vhffsfssync_watch *watch) {
DIR *d;
+ char *pathname;
+
+ pathname = vhffsfssync_pathname(watch, NULL);
+ d = opendir(pathname);
+ free(pathname);
- d = opendir(pathname);
if(d) {
struct dirent *dir;
while( (dir = readdir(d)) ) {
if( strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") ) {
- char *path;
- path = g_strdup_printf("%s/%s", pathname, dir->d_name);
-
// recursivity is done through vhffsfssync_manage_event_create()
// which calls this function
- vhffsfssync_manage_event_create(inotifyfd, path);
- free(path);
+ vhffsfssync_manage_event_create(inotifyfd, watch, dir->d_name);
}
}
closedir(d);
@@ -1594,7 +1625,7 @@
int main(int argc, char *argv[]) {
int inotifyfd, flags;
- int wd;
+ vhffsfssync_watch *watch;
int listenfd, opt;
struct sockaddr_in src;
@@ -1683,10 +1714,10 @@
/* -- inotify stuff -- */
- vhffsfssync_wd_to_path = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
- vhffsfssync_path_to_wd = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+ vhffsfssync_wd_to_watch = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, NULL);
+ vhffsfssync_cookie.watch = NULL;
vhffsfssync_cookie.id = 0;
- vhffsfssync_cookie.from = NULL;
+ vhffsfssync_cookie.filename = NULL;
inotifyfd = inotify_init();
@@ -1697,8 +1728,8 @@
fcntl(inotifyfd, F_SETFL, flags);
}
- wd = vhffsfssync_add_watch_recursively(inotifyfd, root, VHFFSFSSYNC_WATCH_MASK);
- if(wd < 0) {
+ watch = vhffsfssync_add_watch_recursively(inotifyfd, NULL, root, VHFFSFSSYNC_WATCH_MASK);
+ if(!watch) {
fprintf(stderr, "Maximum number of watches probably reached, consider adding more or fixing what is being wrong before running me again (strace is your friend)... byebye!\n");
return -1;
}