Skip to content

Commit ba480d3

Browse files
addaleaxtargos
authored andcommitted
src: use only one tracing write fs req at a time
Concurrent writes to the same fd are generally not ideal, since it’s not generally guaranteed that data from those writes will end up on disk in the right order. PR-URL: #21867 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
1 parent 6b58746 commit ba480d3

File tree

2 files changed

+49
-30
lines changed

2 files changed

+49
-30
lines changed

src/tracing/node_trace_writer.cc

+45-26
Original file line numberDiff line numberDiff line change
@@ -158,38 +158,57 @@ void NodeTraceWriter::Flush(bool blocking) {
158158

159159
void NodeTraceWriter::WriteToFile(std::string&& str, int highest_request_id) {
160160
if (fd_ == -1) return;
161-
WriteRequest* write_req = new WriteRequest();
162-
write_req->str = std::move(str);
163-
write_req->writer = this;
164-
write_req->highest_request_id = highest_request_id;
165-
uv_buf_t uv_buf = uv_buf_init(const_cast<char*>(write_req->str.c_str()),
166-
write_req->str.length());
167-
request_mutex_.Lock();
168-
// Manage a queue of WriteRequest objects because the behavior of uv_write is
169-
// undefined if the same WriteRequest object is used more than once
170-
// between WriteCb calls. In addition, this allows us to keep track of the id
171-
// of the latest write request that actually been completed.
172-
write_req_queue_.push(write_req);
173-
request_mutex_.Unlock();
174-
int err = uv_fs_write(tracing_loop_, reinterpret_cast<uv_fs_t*>(write_req),
175-
fd_, &uv_buf, 1, -1, WriteCb);
161+
162+
uv_buf_t buf = uv_buf_init(nullptr, 0);
163+
{
164+
Mutex::ScopedLock lock(request_mutex_);
165+
write_req_queue_.emplace(WriteRequest {
166+
std::move(str), highest_request_id
167+
});
168+
if (write_req_queue_.size() == 1) {
169+
buf = uv_buf_init(
170+
const_cast<char*>(write_req_queue_.front().str.c_str()),
171+
write_req_queue_.front().str.length());
172+
}
173+
}
174+
// Only one write request for the same file descriptor should be active at
175+
// a time.
176+
if (buf.base != nullptr && fd_ != -1) {
177+
StartWrite(buf);
178+
}
179+
}
180+
181+
void NodeTraceWriter::StartWrite(uv_buf_t buf) {
182+
int err = uv_fs_write(
183+
tracing_loop_, &write_req_, fd_, &buf, 1, -1,
184+
[](uv_fs_t* req) {
185+
NodeTraceWriter* writer =
186+
ContainerOf(&NodeTraceWriter::write_req_, req);
187+
writer->AfterWrite();
188+
});
176189
CHECK_EQ(err, 0);
177190
}
178191

179-
void NodeTraceWriter::WriteCb(uv_fs_t* req) {
180-
WriteRequest* write_req = ContainerOf(&WriteRequest::req, req);
181-
CHECK_GE(write_req->req.result, 0);
192+
void NodeTraceWriter::AfterWrite() {
193+
CHECK_GE(write_req_.result, 0);
194+
uv_fs_req_cleanup(&write_req_);
182195

183-
NodeTraceWriter* writer = write_req->writer;
184-
int highest_request_id = write_req->highest_request_id;
196+
uv_buf_t buf = uv_buf_init(nullptr, 0);
185197
{
186-
Mutex::ScopedLock scoped_lock(writer->request_mutex_);
187-
CHECK_EQ(write_req, writer->write_req_queue_.front());
188-
writer->write_req_queue_.pop();
189-
writer->highest_request_id_completed_ = highest_request_id;
190-
writer->request_cond_.Broadcast(scoped_lock);
198+
Mutex::ScopedLock scoped_lock(request_mutex_);
199+
int highest_request_id = write_req_queue_.front().highest_request_id;
200+
write_req_queue_.pop();
201+
highest_request_id_completed_ = highest_request_id;
202+
request_cond_.Broadcast(scoped_lock);
203+
if (!write_req_queue_.empty()) {
204+
buf = uv_buf_init(
205+
const_cast<char*>(write_req_queue_.front().str.c_str()),
206+
write_req_queue_.front().str.length());
207+
}
208+
}
209+
if (buf.base != nullptr && fd_ != -1) {
210+
StartWrite(buf);
191211
}
192-
delete write_req;
193212
}
194213

195214
// static

src/tracing/node_trace_writer.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@ class NodeTraceWriter : public AsyncTraceWriter {
2727

2828
private:
2929
struct WriteRequest {
30-
uv_fs_t req;
31-
NodeTraceWriter* writer;
3230
std::string str;
3331
int highest_request_id;
3432
};
3533

36-
static void WriteCb(uv_fs_t* req);
34+
void AfterWrite();
35+
void StartWrite(uv_buf_t buf);
3736
void OpenNewFileForStreaming();
3837
void WriteToFile(std::string&& str, int highest_request_id);
3938
void WriteSuffix();
@@ -56,7 +55,8 @@ class NodeTraceWriter : public AsyncTraceWriter {
5655
// Used to wait until async handles have been closed.
5756
ConditionVariable exit_cond_;
5857
int fd_ = -1;
59-
std::queue<WriteRequest*> write_req_queue_;
58+
uv_fs_t write_req_;
59+
std::queue<WriteRequest> write_req_queue_;
6060
int num_write_requests_ = 0;
6161
int highest_request_id_completed_ = 0;
6262
int total_traces_ = 0;

0 commit comments

Comments
 (0)