forked from facebook/watchman
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCookieSync.cpp
117 lines (96 loc) · 2.71 KB
/
CookieSync.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* Copyright 2012-present Facebook, Inc.
* Licensed under the Apache License, Version 2.0 */
#include "watchman.h"
namespace watchman {
CookieSync::CookieSync(const w_string& dir) {
setCookieDir(dir);
}
void CookieSync::setCookieDir(const w_string& dir) {
cookieDir_ = dir;
char hostname[256];
gethostname(hostname, sizeof(hostname));
hostname[sizeof(hostname) - 1] = '\0';
cookiePrefix_ = w_string::printf(
"%.*s%c" WATCHMAN_COOKIE_PREFIX "%s-%d-",
int(cookieDir_.size()),
cookieDir_.data(),
WATCHMAN_DIR_SEP,
hostname,
int(getpid()));
}
bool CookieSync::syncToNow(std::chrono::milliseconds timeout) {
Cookie cookie;
w_stm_t file;
int errcode = 0;
auto cookie_lock = std::unique_lock<std::mutex>(cookie.mutex);
/* generate a cookie name: cookie prefix + id */
auto path_str = w_string::printf(
"%.*s%" PRIu32,
int(cookiePrefix_.size()),
cookiePrefix_.data(),
serial_++);
/* insert our cookie in the map */
{
auto wlock = cookies_.wlock();
auto& map = *wlock;
map[path_str] = &cookie;
}
/* compute deadline */
auto deadline = std::chrono::system_clock::now() + timeout;
/* touch the file */
file = w_stm_open(
path_str.c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0700);
if (!file) {
errcode = errno;
w_log(
W_LOG_ERR,
"sync_to_now: creat(%s) failed: %s\n",
path_str.c_str(),
strerror(errcode));
goto out;
}
w_stm_close(file);
w_log(W_LOG_DBG, "sync_to_now [%s] waiting\n", path_str.c_str());
/* timed cond wait (unlocks cookie lock, reacquires) */
if (!cookie.cond.wait_until(
cookie_lock, deadline, [&] { return cookie.seen; })) {
w_log(
W_LOG_ERR,
"sync_to_now: %s timedwait failed: %d: istimeout=%d %s\n",
path_str.c_str(),
errcode,
errcode == ETIMEDOUT,
strerror(errcode));
goto out;
}
w_log(W_LOG_DBG, "sync_to_now [%s] done\n", path_str.c_str());
out:
cookie_lock.unlock();
// can't unlink the file until after the cookie has been observed because
// we don't know which file got changed until we look in the cookie dir
unlink(path_str.c_str());
{
auto map = cookies_.wlock();
map->erase(path_str);
}
if (!cookie.seen) {
errno = errcode;
return false;
}
return true;
}
void CookieSync::notifyCookie(const w_string& path) const {
auto map = cookies_.rlock();
auto cookie_iter = map->find(path);
w_log(
W_LOG_DBG,
"cookie for %s? %s\n",
path.c_str(),
cookie_iter != map->end() ? "yes" : "no");
if (cookie_iter != map->end()) {
auto cookie = cookie_iter->second;
cookie->seen = true;
cookie->cond.notify_one();
}
}
}