@@ -81,6 +81,62 @@ namespace snapshots
81
81
return snapshot;
82
82
}
83
83
84
+ #define THROW_ON_ERROR (x, name ) \
85
+ do \
86
+ { \
87
+ auto rc = x; \
88
+ if (rc == -1 ) \
89
+ { \
90
+ throw std::runtime_error (fmt::format ( \
91
+ " Error ({}) writing snapshot {} in " #x, strerror (errno), name)); \
92
+ } \
93
+ } while (0 )
94
+
95
+ struct AsyncSnapshotSyncAndRename
96
+ {
97
+ // Inputs, populated at construction
98
+ const std::filesystem::path dir;
99
+ const std::string tmp_file_name;
100
+ const int snapshot_fd;
101
+
102
+ // Outputs, populated by callback
103
+ std::string committed_file_name = {};
104
+ };
105
+
106
+ static void on_snapshot_sync_and_rename (uv_work_t * req)
107
+ {
108
+ auto data = static_cast <AsyncSnapshotSyncAndRename*>(req->data );
109
+
110
+ {
111
+ asynchost::TimeBoundLogger log_if_slow (
112
+ fmt::format (" Committing snapshot - fsync({})" , data->tmp_file_name ));
113
+ fsync (data->snapshot_fd );
114
+ }
115
+
116
+ close (data->snapshot_fd );
117
+
118
+ // e.g. snapshot_100_105.committed
119
+ data->committed_file_name =
120
+ fmt::format (" {}{}" , data->tmp_file_name , snapshot_committed_suffix);
121
+ const auto full_committed_path = data->dir / data->committed_file_name ;
122
+
123
+ const auto full_tmp_path = data->dir / data->tmp_file_name ;
124
+ files::rename (full_tmp_path, full_committed_path);
125
+ }
126
+
127
+ static void on_snapshot_sync_and_rename_complete (uv_work_t * req, int status)
128
+ {
129
+ auto data = static_cast <AsyncSnapshotSyncAndRename*>(req->data );
130
+
131
+ LOG_INFO_FMT (
132
+ " Renamed temporary snapshot {} to {}" ,
133
+ data->tmp_file_name ,
134
+ data->committed_file_name );
135
+
136
+ delete data;
137
+ delete req;
138
+ }
139
+
84
140
void commit_snapshot (
85
141
::consensus::Index snapshot_idx,
86
142
const uint8_t * receipt_data,
@@ -130,42 +186,40 @@ namespace snapshots
130
186
{
131
187
const auto & snapshot = it->second .snapshot ;
132
188
133
- #define THROW_ON_ERROR (x ) \
134
- do \
135
- { \
136
- auto rc = x; \
137
- if (rc == -1 ) \
138
- { \
139
- throw std::runtime_error (fmt::format ( \
140
- " Error ({}) writing snapshot {} in " #x, errno, file_name)); \
141
- } \
142
- } while (0 )
143
-
144
189
THROW_ON_ERROR (
145
- write (snapshot_fd, snapshot->data (), snapshot->size ()));
146
- THROW_ON_ERROR (write (snapshot_fd, receipt_data, receipt_size));
147
-
148
- THROW_ON_ERROR (fsync (snapshot_fd));
149
- THROW_ON_ERROR (close (snapshot_fd));
150
-
151
- #undef THROW_ON_ERROR
190
+ write (snapshot_fd, snapshot->data (), snapshot->size ()),
191
+ file_name);
192
+ THROW_ON_ERROR (
193
+ write (snapshot_fd, receipt_data, receipt_size), file_name);
152
194
153
195
LOG_INFO_FMT (
154
- " New snapshot file written to {} [{} bytes]" ,
196
+ " New snapshot file written to {} [{} bytes] (unsynced) " ,
155
197
file_name,
156
198
snapshot->size () + receipt_size);
157
199
158
- // e.g. snapshot_100_105.committed
159
- const auto committed_file_name =
160
- fmt::format (" {}{}" , file_name, snapshot_committed_suffix);
161
- const auto full_committed_path =
162
- snapshot_dir / committed_file_name;
200
+ // Call fsync and rename on a worker-thread via uv async, as they
201
+ // may be slow
202
+ uv_work_t * work_handle = new uv_work_t ;
163
203
164
- files::rename (full_snapshot_path, full_committed_path);
165
- LOG_INFO_FMT (
166
- " Renamed temporary snapshot {} to committed {}" ,
167
- file_name,
168
- committed_file_name);
204
+ {
205
+ auto * data = new AsyncSnapshotSyncAndRename{
206
+ .dir = snapshot_dir,
207
+ .tmp_file_name = file_name,
208
+ .snapshot_fd = snapshot_fd};
209
+
210
+ work_handle->data = data;
211
+ }
212
+
213
+ #ifdef TEST_MODE_EXECUTE_SYNC_INLINE
214
+ on_snapshot_sync_and_rename (work_handle);
215
+ on_snapshot_sync_and_rename_complete (work_handle, 0 );
216
+ #else
217
+ uv_queue_work (
218
+ uv_default_loop (),
219
+ work_handle,
220
+ &on_snapshot_sync_and_rename,
221
+ &on_snapshot_sync_and_rename_complete);
222
+ #endif
169
223
}
170
224
171
225
pending_snapshots.erase (it);
@@ -184,6 +238,7 @@ namespace snapshots
184
238
e.what ());
185
239
}
186
240
}
241
+ #undef THROW_ON_ERROR
187
242
188
243
std::optional<std::pair<fs::path, fs::path>>
189
244
find_latest_committed_snapshot ()
0 commit comments