use serde::{Deserialize, Serialize};
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::error::{Error, Result};
pub const SCHEMA_VERSION: u32 = 6;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PendingTombstones {
pub segment_id: u64,
pub doc_ids: Vec<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Meta {
pub schema_version: u32,
pub segments: Vec<u64>,
pub next_segment_id: u64,
pub last_indexed: u64,
pub doc_count: u64,
pub symbol_count: u64,
#[serde(default)]
pub indexed_git_head: String,
#[serde(default)]
pub indexed_branch: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub pending_tombstones: Vec<PendingTombstones>,
}
impl Default for Meta {
fn default() -> Self {
Self {
schema_version: SCHEMA_VERSION,
segments: Vec::new(),
next_segment_id: 0,
last_indexed: 0,
doc_count: 0,
symbol_count: 0,
indexed_git_head: String::new(),
indexed_branch: String::new(),
pending_tombstones: Vec::new(),
}
}
}
impl Meta {
pub fn load(path: &Path) -> Result<Meta> {
match std::fs::read(path) {
Ok(bytes) => {
let meta: Meta = serde_json::from_slice(&bytes)?;
if meta.schema_version != SCHEMA_VERSION {
return Err(Error::Corrupt(format!(
"index schema version {} != supported {}; run `greplm index` to rebuild",
meta.schema_version, SCHEMA_VERSION
)));
}
Ok(meta)
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(Meta::default()),
Err(e) => Err(Error::io(path, e)),
}
}
pub fn save(&self, path: &Path) -> Result<()> {
let bytes = serde_json::to_vec_pretty(self)?;
crate::fsutil::write_atomic(path, &bytes)
}
pub fn record_git_head(&mut self, root: &Path) {
if let Some((sha, branch)) = crate::git::head(root) {
self.indexed_git_head = sha;
self.indexed_branch = branch;
}
}
pub fn touch_now(&mut self) {
self.last_indexed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
}
pub fn alloc_segment(&mut self) -> u64 {
let id = self.next_segment_id;
self.next_segment_id += 1;
id
}
}