Repository: meilisearch/meilisearch
File: crates/milli/src/database_stats.rs (Rust)

Code before:
use heed::types::Bytes;
use heed::Database;
use heed::RoTxn;
use serde::{Deserialize, Serialize};

use crate::Result;

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
/// The stats of a database.
pub struct DatabaseStats {
    /// The number of entries in the database.
    number_of_entries: u64,
    /// The total size of the keys in the database.
    total_key_size: u64,
    /// The total size of the values in the database.
    total_value_size: u64,
    /// The maximum size of a key in the database.
    max_key_size: u64,
    /// The maximum size of a value in the database.
    max_value_size: u64,
    /// The minimum size of a key in the database.
    min_key_size: u64,
    /// The minimum size of a value in the database.
    min_value_size: u64,
}

impl DatabaseStats {
    /// Returns the stats of the database.
    ///
    /// This function iterates over the whole database and computes the stats.
    /// It is not efficient and should be cached somewhere.
    pub(crate) fn new(database: Database<Bytes, Bytes>, rtxn: &RoTxn<'_>) -> Result<Self> {
        let mut database_stats = Self {
            number_of_entries: 0,
            total_key_size: 0,
            total_value_size: 0,
            max_key_size: 0,
            max_value_size: 0,
            min_key_size: u64::MAX,
            min_value_size: u64::MAX,
        };

        let mut iter = database.iter(rtxn)?;
        while let Some((key, value)) = iter.next().transpose()? {
            let key_size = key.len() as u64;
            let value_size = value.len() as u64;

Review comment (suggestion):
Oh wow, are we sure we want something like that?
I guess we won’t have the time for anything else before Thursday but can’t we compute it iteratively during the indexing pipeline since we know which documents are added, updated or removed and from which fields? 🤔 

Code after:
use heed::types::Bytes;
use heed::Database;
use heed::RoTxn;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
/// The stats of a database.
pub struct DatabaseStats {
    /// The number of entries in the database.
    number_of_entries: u64,
    /// The total size of the keys in the database.
    total_key_size: u64,
    /// The total size of the values in the database.
    total_value_size: u64,
}

impl DatabaseStats {
    /// Returns the stats of the database.
    ///
    /// This function iterates over the whole database and computes the stats.
    /// It is not efficient and should be cached somewhere.
    pub(crate) fn new(database: Database<Bytes, Bytes>, rtxn: &RoTxn<'_>) -> heed::Result<Self> {
        let mut database_stats =
            Self { number_of_entries: 0, total_key_size: 0, total_value_size: 0 };

        let mut iter = database.iter(rtxn)?;
        while let Some((key, value)) = iter.next().transpose()? {
            let key_size = key.len() as u64;
            let value_size = value.len() as u64;
            database_stats.total_key_size += key_size;
            database_stats.total_value_size += value_size;
        }

        database_stats.number_of_entries = database.len(rtxn)?;

        Ok(database_stats)
    }

    /// Recomputes the stats of the database and returns the new stats.
    ///
    /// This function is used to update the stats of the database when some keys are modified.
    /// It is more efficient than the `new` function because it does not iterate over the whole database but only the modified keys comparing the before and after states.
    pub(crate) fn recompute<I, K>(
        mut stats: Self,
        database: Database<Bytes, Bytes>,
        before_rtxn: &RoTxn<'_>,