Repository: qdrant/qdrant
File: lib/shard/src/wal.rs (Rust)

Code before:
            wal,
            options: wal_options,
            first_index,
            _record: PhantomData,
        })
    }

    /// Write a record to the WAL but does guarantee durability.
    pub fn write(&mut self, record: &WalSerializedRecord<R>) -> Result<u64> {
        self.wal
            .append(&record.record)
            .map_err(|err| WalError::WriteWalError(format!("{err:?}")))
    }

    pub fn read_all(
        &self,
        with_acknowledged: bool,
    ) -> impl DoubleEndedIterator<Item = (u64, R)> + '_ {
        if with_acknowledged {
            self.read(self.first_closed_index())
        } else {
            self.read(self.first_index())
        }
    }

    pub fn read_single_record(&self, idx: u64) -> Option<WalSerializedRecord<R>> {
        if let Some(entry) = self.wal.entry(idx) {
            Some(WalSerializedRecord::<R> {
                record: entry.to_vec(),
                _phantom: PhantomData,
            })
        } else {
            None
        }
    }

    pub fn read(&self, from: u64) -> impl DoubleEndedIterator<Item = (u64, R)> + '_ {
        // We have to explicitly do `from..self.first_index() + self.len(false)`, instead of more
        // concise `from..=self.last_index()`, because if the WAL is empty, `Wal::last_index`
        // returns `Wal::first_index`, so we end up with `1..=1` instead of an empty range. 😕

        let to = self.first_index() + self.len(false);
        self.read_range(from..to)
    }

    pub fn read_range(&self, range: Range<u64>) -> impl DoubleEndedIterator<Item = (u64, R)> + '_ {
        range.map(move |idx| {
            let record_bin = self
                .wal
                .entry(idx)
                .unwrap_or_else(|| panic!("Can't read entry {idx} from WAL"));

Review comment (suggestion):
nit: I would prefer `read_raw_record`

as https://github.com/qdrant/qdrant/pull/8093/changes#r2792096551 is getting my vote

Code after:
    /// Write a record to the WAL but does guarantee durability.
    pub fn write(&mut self, record: &WalRawRecord<R>) -> Result<u64> {
        self.wal
            .append(&record.record)
            .map_err(|err| WalError::WriteWalError(format!("{err:?}")))
    }

    pub fn read_all(
        &self,
        with_acknowledged: bool,
    ) -> impl DoubleEndedIterator<Item = (u64, R)> + '_ {
        if with_acknowledged {
            self.read(self.first_closed_index())
        } else {
            self.read(self.first_index())
        }
    }

    pub fn read_raw_record(&self, idx: u64) -> Option<WalRawRecord<R>> {
        if let Some(entry) = self.wal.entry(idx) {
            Some(WalRawRecord::<R> {
                record: entry.to_vec(),
                _phantom: PhantomData,
            })
        } else {
            None
        }
    }

    pub fn read(&self, from: u64) -> impl DoubleEndedIterator<Item = (u64, R)> + '_ {
        // We have to explicitly do `from..self.first_index() + self.len(false)`, instead of more
        // concise `from..=self.last_index()`, because if the WAL is empty, `Wal::last_index`
        // returns `Wal::first_index`, so we end up with `1..=1` instead of an empty range. 😕

        let to = self.first_index() + self.len(false);
        self.read_range(from..to)
    }

    pub fn read_range(&self, range: Range<u64>) -> impl DoubleEndedIterator<Item = (u64, R)> + '_ {
        range.map(move |idx| {
            let record_bin = self
                .wal
                .entry(idx)
                .unwrap_or_else(|| panic!("Can't read entry {idx} from WAL"));

            let record: R = WalRawRecord::deserialize_from(&record_bin)
                .expect("Can't deserialize entry, probably corrupted WAL or version mismatch");

            (idx, record)
        })
    }