MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / append

Method append

nodedb-wal/src/writer.rs:274–339  ·  view source on GitHub ↗

Append a record to the WAL. Returns the assigned LSN. The record is written to the in-memory buffer. Call `sync()` to flush to disk and make the write durable. `database_id` is stored in header bytes 34-41. Pass `0` for the default database (backward-compatible with pre-existing records).

(
        &mut self,
        record_type: u32,
        tenant_id: u64,
        vshard_id: u32,
        database_id: u64,
        payload: &[u8],
    )

Source from the content-addressed store, hash-verified

272 /// `database_id` is stored in header bytes 34-41. Pass `0` for the
273 /// default database (backward-compatible with pre-existing records).
274 pub fn append(
275 &mut self,
276 record_type: u32,
277 tenant_id: u64,
278 vshard_id: u32,
279 database_id: u64,
280 payload: &[u8],
281 ) -> Result<u64> {
282 if self.sealed {
283 return Err(WalError::Sealed);
284 }
285
286 let lsn = self.next_lsn.fetch_add(1, Ordering::Relaxed);
287 let preamble_bytes = self.segment_preamble.as_ref().map(|p| p.to_bytes());
288 let record = WalRecord::new(
289 record_type,
290 lsn,
291 tenant_id,
292 vshard_id,
293 database_id,
294 payload.to_vec(),
295 self.encryption_ring.as_ref().map(|r| r.current()),
296 preamble_bytes.as_ref(),
297 )?;
298
299 // Write to double-write buffer (deferred — no fsync yet).
300 // The DWB is fsynced in batch during `sync()`, before the WAL fsync.
301 // This amortizes DWB fsync cost across the entire group commit batch.
302 //
303 // DWB failure is non-fatal for the write itself (the WAL is the
304 // authoritative store), but we log a warning because it means
305 // torn-write recovery is degraded. If the DWB is persistently
306 // broken, we detach it to avoid repeated error noise.
307 if let Some(dwb) = &mut self.double_write
308 && let Err(e) = dwb.write_record_deferred(&record)
309 {
310 tracing::warn!(
311 lsn = lsn,
312 error = %e,
313 "DWB write failed — torn-write protection degraded, detaching DWB"
314 );
315 self.double_write = None;
316 }
317
318 let header_bytes = record.header.to_bytes();
319 let total_size = HEADER_SIZE + record.payload.len();
320
321 // If this record doesn't fit in the remaining buffer, flush first.
322 if self.buffer.remaining() < total_size {
323 self.flush_buffer()?;
324 }
325
326 // If the record is larger than the entire buffer, we have a problem.
327 // This shouldn't happen with MAX_WAL_PAYLOAD_SIZE checks, but guard anyway.
328 if total_size > self.buffer.capacity() {
329 return Err(WalError::PayloadTooLarge {
330 size: record.payload.len(),
331 max: self.buffer.capacity() - HEADER_SIZE,

Callers 15

wal_append_fsync_1kFunction · 0.45
wal_append_only_10kFunction · 0.45
submitMethod · 0.45
recover_with_recordsFunction · 0.45
recover_truncated_walFunction · 0.45
openMethod · 0.45
open_with_start_lsnMethod · 0.45
lsn_incrementsFunction · 0.45

Calls 10

write_record_deferredMethod · 0.80
flush_bufferMethod · 0.80
as_refMethod · 0.45
to_bytesMethod · 0.45
to_vecMethod · 0.45
currentMethod · 0.45
lenMethod · 0.45
remainingMethod · 0.45
capacityMethod · 0.45
writeMethod · 0.45

Tested by 15

recover_with_recordsFunction · 0.36
recover_truncated_walFunction · 0.36
lsn_incrementsFunction · 0.36
lazy_read_all_payloadsFunction · 0.36
lazy_skip_non_matchingFunction · 0.36
mmap_reader_basicFunction · 0.36
replay_mmap_from_lsnFunction · 0.36