fsevents: use FlagNoDefer for FSEventStreamCreate

Otherwise `FSEventStreamCreate()` will coalesce events, even if they're
happening in the interval, bigger than supplied `latency`. In other
words, if this flag is not set events will happen in separate callback
only if there was a delay bigger than `latency` between two consecutive
events.
This commit is contained in:
Fedor Indutny 2013-11-01 20:28:40 +04:00
parent c6ecf97aaf
commit 0f5c28b684
3 changed files with 98 additions and 17 deletions

View File

@ -316,10 +316,21 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
ctx.release = NULL;
ctx.copyDescription = NULL;
latency = 0.15;
latency = 0.05;
/* Set appropriate flags */
flags = kFSEventStreamCreateFlagFileEvents;
/* Explanation of selected flags:
* 1. NoDefer - without this flag, events that are happening continuously
* (i.e. each event is happening after time interval less than `latency`,
* counted from previous event), will be deferred and passed to callback
* once they'll either fill whole OS buffer, or when this continuous stream
* will stop (i.e. there'll be delay between events, bigger than
* `latency`).
* Specifying this flag will invoke callback after `latency` time passed
* since event.
* 2. FileEvents - fire callback for file changes too (by default it is firing
* it only for directory changes).
*/
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
/*
* NOTE: It might sound like a good idea to remember last seen StreamEventId,

View File

@ -241,6 +241,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop);
/* OSX < 10.7 has no file events, polyfill them */
#ifndef MAC_OS_X_VERSION_10_7
static const int kFSEventStreamCreateFlagNoDefer = 0x00000002;
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;

View File

@ -36,11 +36,21 @@
#endif
static uv_fs_event_t fs_event;
static const char file_prefix[] = "fsevent-";
static uv_timer_t timer;
static int timer_cb_called = 0;
static int close_cb_called = 0;
static int fs_event_cb_called = 0;
static int timer_cb_touch_called = 0;
static int timer_cb_called;
static int close_cb_called;
static const int fs_event_file_count = 128;
static int fs_event_created;
static int fs_event_cb_called;
#if defined(PATH_MAX)
static char fs_event_filename[PATH_MAX];
#else
static char fs_event_filename[1024];
#endif /* defined(PATH_MAX) */
static int timer_cb_touch_called;
static void fs_event_unlink_files(uv_timer_t* handle, int status);
static void create_dir(uv_loop_t* loop, const char* name) {
int r;
@ -107,6 +117,69 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
uv_close((uv_handle_t*)handle, close_cb);
}
static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
const char* filename,
int events,
int status) {
fs_event_cb_called++;
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_RENAME);
ASSERT(filename == NULL ||
strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
/* Stop watching dir when received events about all files:
* both create and close events */
if (fs_event_cb_called == 2 * fs_event_file_count) {
ASSERT(0 == uv_fs_event_stop(handle));
uv_close((uv_handle_t*) handle, close_cb);
}
}
static const char* fs_event_get_filename(int i) {
snprintf(fs_event_filename,
sizeof(fs_event_filename),
"watch_dir/%s%d",
file_prefix,
i);
return fs_event_filename;
}
static void fs_event_create_files(uv_timer_t* handle, int status) {
int i;
/* Already created all files */
if (fs_event_created == fs_event_file_count) {
uv_close((uv_handle_t*) &timer, close_cb);
return;
}
/* Create all files */
for (i = 0; i < 16; i++, fs_event_created++)
create_file(handle->loop, fs_event_get_filename(i));
/* And unlink them */
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 50, 0));
}
void fs_event_unlink_files(uv_timer_t* handle, int status) {
int r;
int i;
/* NOTE: handle might be NULL if invoked not as timer callback */
/* Unlink all files */
for (i = 0; i < 16; i++) {
r = remove(fs_event_get_filename(i));
if (handle != NULL)
ASSERT(r == 0);
}
/* And create them again */
if (handle != NULL)
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 50, 0));
}
static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
int events, int status) {
++fs_event_cb_called;
@ -148,12 +221,6 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
}
}
static void timer_cb_dir(uv_timer_t* handle, int status) {
++timer_cb_called;
create_file(handle->loop, "watch_dir/file1");
uv_close((uv_handle_t*)handle, close_cb);
}
static void timer_cb_file(uv_timer_t* handle, int status) {
++timer_cb_called;
@ -184,6 +251,7 @@ TEST_IMPL(fs_event_watch_dir) {
int r;
/* Setup */
fs_event_unlink_files(NULL, 0);
remove("watch_dir/file2");
remove("watch_dir/file1");
remove("watch_dir/");
@ -191,20 +259,21 @@ TEST_IMPL(fs_event_watch_dir) {
r = uv_fs_event_init(loop, &fs_event);
ASSERT(r == 0);
r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_dir", 0);
r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
ASSERT(r == 0);
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
r = uv_timer_start(&timer, timer_cb_dir, 100, 0);
r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
ASSERT(r == 0);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(fs_event_cb_called == 1);
ASSERT(timer_cb_called == 1);
ASSERT(fs_event_cb_called == 2 * fs_event_file_count);
ASSERT(fs_event_created == fs_event_file_count);
ASSERT(close_cb_called == 2);
/* Cleanup */
fs_event_unlink_files(NULL, 0);
remove("watch_dir/file2");
remove("watch_dir/file1");
remove("watch_dir/");