Everett
Loading...
Searching...
No Matches
private_construction.h
Go to the documentation of this file.
1
12#pragma once
13
15
16#include <memory>
17
18#if defined(__APPLE__) || defined(__linux__)
19#include <sys/file.h>
20#endif
21
22namespace everett {
23 // Share the lease with every snapshot and worker that can still use the
24 // private frontier. A different process may recover only an unlocked lease.
25 // A lock name is removed only after its durable release event: an active
26 // scope never has two lock identities. The file contains no values.
27 template <class P> struct private_construction {
28 static std::shared_ptr<private_construction> create(std::filesystem::path const & root) {
29 auto result = std::shared_ptr<private_construction>(new private_construction(
30 std::filesystem::canonical(root), random_object_ids{}()));
31 result->lease_ = acquire(result->path(), true);
32 sync_name(result->root_, result->lease_);
33 auto catalog = sqlite_catalog<P>::open(result->root_);
34 catalog.begin_private_scope(random_object_ids{}().hex(), result->id_);
35 return result;
36 }
40 if (lease_ < 0) return;
41 try {
42 auto catalog = sqlite_catalog<P>::open(root_);
43 catalog.release_private_scope(random_object_ids{}().hex(), id_);
45 } catch (...) {
46 // Recovery finds either an active scope or an orphan lease name.
47 // Destruction cannot report an uncertain SQLite outcome as a
48 // successful cleanup.
49 }
51 }
52 catalog_options options() const { return {250, id_}; }
53 object_id const & identity() const & noexcept { return id_; }
54 object_id const & identity() const && = delete;
55 static std::size_t recover(std::filesystem::path const & root) {
56 auto location = std::filesystem::canonical(root);
57 auto catalog = sqlite_catalog<P>::open(location);
58 using state = typename sqlite_catalog<P>::private_scope_state;
59 std::size_t count = 0;
60 for (auto const & id : catalog.private_scopes()) {
61 int fd;
62 try { fd = acquire(path(location, id), false); }
63 catch (std::system_error const & error) {
64 if (error.code() != std::errc::no_such_file_or_directory) throw;
65 // Another owner may have released and removed its lease since the
66 // initial query. A missing *active* lease remains an error.
67 if (catalog.scope_state(id) == state::active) throw;
68 continue;
69 }
70 if (fd < 0) continue; // A live owner still has this exact lease.
71 held lease{fd};
72 if (catalog.scope_state(id) != state::active) {
73 remove_name(location, path(location, id));
74 continue;
75 }
76 catalog.release_private_scope(random_object_ids{}().hex(), id);
77 remove_name(location, path(location, id));
78 ++count;
79 }
80 // A crash can leave a name before scope registration or after release.
81 // The lock, followed by a fresh catalog read, distinguishes those from
82 // live construction. Only canonical lease names belong to this sweep.
83 for (auto const & entry : std::filesystem::directory_iterator(location)) {
84 auto name = entry.path().filename().string();
85 if (name.size() != 46 || !name.starts_with(".private-") || !name.ends_with(".lock")) continue;
86 auto hex = std::string_view(name).substr(9, 32);
87 if (hex.find_first_not_of("0123456789abcdef") != std::string_view::npos) continue;
88 auto id = object_id::from_hex(hex);
89 int fd;
90 try { fd = acquire(entry.path(), false); }
91 catch (std::system_error const & error) {
92 if (error.code() == std::errc::no_such_file_or_directory) continue;
93 throw;
94 }
95 if (fd < 0) continue;
96 held lease{fd};
97 if (catalog.scope_state(id) != state::active) remove_name(location, entry.path());
98 }
99 return count;
100 }
101 private:
102 std::filesystem::path root_;
104 int lease_ = -1;
105 struct held { int fd; ~held() { private_construction::close(fd); } };
106 private_construction(std::filesystem::path root, object_id id)
107 : root_(std::move(root)), id_(std::move(id)) {}
108 static std::filesystem::path path(std::filesystem::path const & root, object_id const & id) {
109 return root / (".private-" + id.hex() + ".lock");
110 }
111 std::filesystem::path path() const { return path(root_, id_); }
112 static void close(int fd) noexcept {
113#if defined(__APPLE__) || defined(__linux__)
114 (void)::close(fd);
115#else
116 (void)fd;
117#endif
118 }
119 static int acquire(std::filesystem::path const & path, bool create) {
120#if defined(__APPLE__) || defined(__linux__)
121 auto fd = ::open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | (create ? O_CREAT | O_EXCL : 0), 0600);
122 if (fd < 0) throw std::system_error(errno, std::generic_category(), "open private construction lease");
123 struct stat info{};
124 if (::fstat(fd, &info) || !S_ISREG(info.st_mode)) {
125 auto error = errno ? errno : EINVAL; close(fd);
126 throw std::system_error(error, std::generic_category(), "private construction lease is not regular");
127 }
128 if (::flock(fd, LOCK_EX | LOCK_NB)) {
129 auto error = errno; close(fd);
130 if (!create && (error == EWOULDBLOCK || error == EAGAIN)) return -1;
131 throw std::system_error(error, std::generic_category(), "lock private construction lease");
132 }
133 // Recovery can acquire a just-created name before its creator locks it.
134 // Never register a scope after that name was removed under the lock.
135 if (::fstat(fd, &info) || info.st_nlink != 1) {
136 auto error = errno; close(fd);
137 throw std::system_error(info.st_nlink != 1 ? ENOENT : error, std::generic_category(),
138 "private construction lease has no unique name");
139 }
140 return fd;
141#else
142 (void)path; (void)create;
143 throw std::system_error(std::make_error_code(std::errc::operation_not_supported), "private construction leases require POSIX");
144#endif
145 }
146 static void sync_name(std::filesystem::path const & root, int fd) {
147#if defined(__APPLE__) || defined(__linux__)
148 if (::fsync(fd)) throw std::system_error(errno, std::generic_category(), "sync private construction lease");
150 auto directory = ops.open_root(root);
151 if (directory < 0) throw std::system_error(errno, std::generic_category(), "open construction lease directory");
152 auto result = ops.sync_directory(directory); auto error = errno;
153 ops.close(directory);
154 if (result) throw std::system_error(error, std::generic_category(), "sync construction lease directory");
155#else
156 (void)root; (void)fd;
157#endif
158 }
159 static void remove_name(std::filesystem::path const & root, std::filesystem::path const & path) {
160#if defined(__APPLE__) || defined(__linux__)
161 if (::unlink(path.c_str()) && errno != ENOENT)
162 throw std::system_error(errno, std::generic_category(), "remove released construction lease");
164 auto directory = ops.open_root(root);
165 if (directory < 0) throw std::system_error(errno, std::generic_category(), "open released lease directory");
166 auto result = ops.sync_directory(directory); auto error = errno;
167 ops.close(directory);
168 if (result) throw std::system_error(error, std::generic_category(), "sync released lease directory");
169#else
170 (void)root; (void)path;
171#endif
172 }
173 };
174}
Definition active_engine.h:18
Seals runtime frontiers and restores named sessions through immutable mappings.
Definition sqlite_catalog.h:39
Definition object_path.h:38
static object_id from_hex(std::string_view hex)
Definition object_path.h:45
Definition object_writer.h:100
Definition private_construction.h:105
int fd
Definition private_construction.h:105
~held()
Definition private_construction.h:105
Definition private_construction.h:27
static std::filesystem::path path(std::filesystem::path const &root, object_id const &id)
Definition private_construction.h:108
std::filesystem::path root_
Definition private_construction.h:102
private_construction & operator=(private_construction const &)=delete
std::filesystem::path path() const
Definition private_construction.h:111
static std::size_t recover(std::filesystem::path const &root)
Definition private_construction.h:55
private_construction(private_construction const &)=delete
static std::shared_ptr< private_construction > create(std::filesystem::path const &root)
Definition private_construction.h:28
catalog_options options() const
Definition private_construction.h:52
object_id id_
Definition private_construction.h:103
~private_construction()
Definition private_construction.h:39
private_construction(std::filesystem::path root, object_id id)
Definition private_construction.h:106
object_id const & identity() const &&=delete
static void sync_name(std::filesystem::path const &root, int fd)
Definition private_construction.h:146
static void close(int fd) noexcept
Definition private_construction.h:112
static void remove_name(std::filesystem::path const &root, std::filesystem::path const &path)
Definition private_construction.h:159
object_id const & identity() const &noexcept
Definition private_construction.h:53
int lease_
Definition private_construction.h:104
static int acquire(std::filesystem::path const &path, bool create)
Definition private_construction.h:119
Definition runtime_store.h:31
private_scope_state
Definition sqlite_catalog.h:435
static sqlite_catalog open(std::filesystem::path const &root, catalog_options options={}, Ops ops={})
Definition sqlite_catalog.h:379