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

Code before:
        }
        Ok(())
    }
}

impl<V> Gridstore<V> {
    /// The number of blocks needed for a given value bytes size
    #[inline]
    fn blocks_for_value(value_size: usize, block_size: usize) -> u32 {
        value_size.div_ceil(block_size).try_into().unwrap()
    }

    /// Create flusher that durably persists all pending changes when invoked
    pub fn flusher(&self) -> Flusher {
        let pending_updates = self.tracker.read().pending_updates.clone();

        let pages = Arc::downgrade(&self.pages);
        let tracker = Arc::downgrade(&self.tracker);
        let bitmask = Arc::downgrade(&self.bitmask);
        let block_size_bytes = self.config.block_size_bytes;

        let is_alive_flush_lock = self.is_alive_flush_lock.handle();

        Box::new(move || {
            // Keep the guard till the end of the flush to prevent concurrent flushes
            let Some(_is_alive_flush_guard) = is_alive_flush_lock.lock_if_alive() else {
                // Segment is cleared, skip flush
                return Ok(());
            };

            let (Some(pages), Some(tracker), Some(bitmask)) =
                (pages.upgrade(), tracker.upgrade(), bitmask.upgrade())
            else {
                return Ok(());
            };

            let mut bitmask_guard = bitmask.upgradable_read();
            bitmask_guard.flush()?;
            for page in pages.read().iter() {
                page.flush()?;
            }

            let old_pointers = tracker.write().write_pending_and_flush(pending_updates)?;
            if old_pointers.is_empty() {
                return Ok(());
            }
            // Update all free blocks in the bitmask
            bitmask_guard.with_upgraded(|guard| {
                for (page_id, pointer_group) in
                    &old_pointers.into_iter().chunk_by(|pointer| pointer.page_id)
                {

Review comment (bug):
I vote to explicitly `drop(is_alive_flush_guard)` at the end of the function. I'm afraid we'll miss this important bit when refactoring in the future. And incorrectly handling this lock will not show immediate problems.

Same for other places we use it.

Code after:
        }
        Ok(())
    }
}

impl<V> Gridstore<V> {
    /// The number of blocks needed for a given value bytes size
    #[inline]
    fn blocks_for_value(value_size: usize, block_size: usize) -> u32 {
        value_size.div_ceil(block_size).try_into().unwrap()
    }

    /// Create flusher that durably persists all pending changes when invoked
    pub fn flusher(&self) -> Flusher {
        let pending_updates = self.tracker.read().pending_updates.clone();

        let pages = Arc::downgrade(&self.pages);
        let tracker = Arc::downgrade(&self.tracker);
        let bitmask = Arc::downgrade(&self.bitmask);
        let block_size_bytes = self.config.block_size_bytes;

        let is_alive_flush_lock = self.is_alive_flush_lock.handle();

        Box::new(move || {
            let Some(is_alive_flush_guard) = is_alive_flush_lock.lock_if_alive() else {
                // Segment is cleared, skip flush
                return Ok(());
            };

            let (Some(pages), Some(tracker), Some(bitmask)) =
                (pages.upgrade(), tracker.upgrade(), bitmask.upgrade())
            else {
                return Ok(());
            };

            let mut bitmask_guard = bitmask.upgradable_read();
            bitmask_guard.flush()?;
            for page in pages.read().iter() {
                page.flush()?;
            }

            let old_pointers = tracker.write().write_pending_and_flush(pending_updates)?;
            if old_pointers.is_empty() {
                return Ok(());
            }
            // Update all free blocks in the bitmask
            bitmask_guard.with_upgraded(|guard| {
                for (page_id, pointer_group) in
                    &old_pointers.into_iter().chunk_by(|pointer| pointer.page_id)
                {
                    let local_ranges = pointer_group.map(|pointer| {