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

Method reserve

nodedb/src/control/sequence/gap_free.rs:73–127  ·  view source on GitHub ↗

Reserve the next gap-free number for a sequence. Blocks if another transaction holds a reservation on this sequence. Returns a handle that must be committed or rolled back — until then, other callers on the same sequence will block. `advance_fn` is called after acquiring the lock to atomically advance the underlying counter.

(
        &self,
        sequence_key: &str,
        advance_fn: impl FnOnce() -> Result<i64, SequenceError>,
    )

Source from the content-addressed store, hash-verified

71 /// `advance_fn` is called after acquiring the lock to atomically advance
72 /// the underlying counter.
73 pub fn reserve(
74 &self,
75 sequence_key: &str,
76 advance_fn: impl FnOnce() -> Result<i64, SequenceError>,
77 ) -> Result<ReservationHandle, SequenceError> {
78 // Get or create the per-sequence lock.
79 let lock = {
80 let mut locks = self.locks.lock().unwrap_or_else(|p| p.into_inner());
81 locks
82 .entry(sequence_key.to_string())
83 .or_insert_with(|| {
84 Arc::new(SequenceLock {
85 locked: Mutex::new(false),
86 unlocked: Condvar::new(),
87 })
88 })
89 .clone()
90 };
91
92 // Wait until no active reservation, then mark as locked.
93 {
94 let mut is_locked = lock.locked.lock().unwrap_or_else(|p| p.into_inner());
95 while *is_locked {
96 is_locked = lock
97 .unlocked
98 .wait(is_locked)
99 .unwrap_or_else(|p| p.into_inner());
100 }
101 *is_locked = true;
102 }
103
104 // Advance the counter while holding the logical lock.
105 let value = match advance_fn() {
106 Ok(v) => v,
107 Err(e) => {
108 // Unlock on advance failure.
109 self.unlock_sequence(&lock);
110 return Err(e);
111 }
112 };
113
114 // Generate reservation ID.
115 let id = {
116 let mut next = self.next_id.lock().unwrap_or_else(|p| p.into_inner());
117 let id = ReservationId(*next);
118 *next += 1;
119 id
120 };
121
122 Ok(ReservationHandle {
123 id,
124 sequence_key: sequence_key.to_string(),
125 value,
126 })
127 }
128
129 /// Commit a reservation: the number is now permanent.
130 /// Releases the per-sequence lock so the next caller can proceed.

Callers 6

reserve_commitFunction · 0.45
reserve_rollbackFunction · 0.45
sequential_reservationsFunction · 0.45
concurrent_serializationFunction · 0.45
feedMethod · 0.45

Calls 6

ReservationIdClass · 0.85
lockMethod · 0.80
entryMethod · 0.80
to_stringMethod · 0.80
unlock_sequenceMethod · 0.80
cloneMethod · 0.45

Tested by 5

reserve_commitFunction · 0.36
reserve_rollbackFunction · 0.36
sequential_reservationsFunction · 0.36
concurrent_serializationFunction · 0.36