@@ -119,18 +119,21 @@ namespace asynchost
119119 }
120120
121121 auto file_path = dir / file_name;
122- if (fs::exists (file_path))
123- {
124- throw std::logic_error (fmt::format (
125- " Cannot create new ledger file {} in main ledger directory {} as it "
126- " already exists" ,
127- file_name,
128- dir));
129- }
122+
123+ // Use exclusive-create mode ("x") to atomically fail if the file
124+ // already exists, avoiding a separate fs::exists() stat call.
130125 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
131- file = fopen (file_path.c_str (), " w+b " );
126+ file = fopen (file_path.c_str (), " w+bx " );
132127 if (file == nullptr )
133128 {
129+ if (errno == EEXIST)
130+ {
131+ throw std::logic_error (fmt::format (
132+ " Cannot create new ledger file {} in main ledger directory {} as "
133+ " it already exists" ,
134+ file_name,
135+ dir));
136+ }
134137 throw std::logic_error (fmt::format (
135138 " Unable to open ledger file {}: {}" ,
136139 file_path,
@@ -535,8 +538,14 @@ namespace asynchost
535538 // truncated on the primary, so we have to make sure that whenever we
536539 // complete the file it doesn't contain anything past the last_idx, which
537540 // can happen on the follower unless explicitly truncated before
538- // completion.
539- truncate (get_last_idx (), /* remove_file_if_empty = */ false );
541+ // completion. This is only necessary when the file was recovered from an
542+ // existing file on disk (from_existing_file is true). For fresh files,
543+ // total_len always matches the physical file size, so avoid a potentially
544+ // expensive truncate.
545+ if (from_existing_file)
546+ {
547+ truncate (get_last_idx (), /* remove_file_if_empty = */ false );
548+ }
540549
541550 fseeko (file, total_len, SEEK_SET);
542551 size_t table_offset = ftello (file);
0 commit comments