1use serde::{Deserialize, Serialize};
4use std::path::Path;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7use crate::error::{Error, Result};
8
9pub const SCHEMA_VERSION: u32 = 2;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Meta {
17 pub schema_version: u32,
18 pub segments: Vec<u64>,
20 pub next_segment_id: u64,
22 pub last_indexed: u64,
24 pub doc_count: u64,
26 pub symbol_count: u64,
28 #[serde(default)]
31 pub indexed_git_head: String,
32 #[serde(default)]
34 pub indexed_branch: String,
35}
36
37impl Default for Meta {
38 fn default() -> Self {
39 Self {
40 schema_version: SCHEMA_VERSION,
41 segments: Vec::new(),
42 next_segment_id: 0,
43 last_indexed: 0,
44 doc_count: 0,
45 symbol_count: 0,
46 indexed_git_head: String::new(),
47 indexed_branch: String::new(),
48 }
49 }
50}
51
52impl Meta {
53 pub fn load(path: &Path) -> Result<Meta> {
54 match std::fs::read(path) {
55 Ok(bytes) => {
56 let meta: Meta = serde_json::from_slice(&bytes)?;
57 if meta.schema_version != SCHEMA_VERSION {
58 return Err(Error::Corrupt(format!(
59 "index schema version {} != supported {}; run `greplm index` to rebuild",
60 meta.schema_version, SCHEMA_VERSION
61 )));
62 }
63 Ok(meta)
64 }
65 Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(Meta::default()),
66 Err(e) => Err(Error::io(path, e)),
67 }
68 }
69
70 pub fn save(&self, path: &Path) -> Result<()> {
71 let bytes = serde_json::to_vec_pretty(self)?;
72 crate::fsutil::write_atomic(path, &bytes)
73 }
74
75 pub fn record_git_head(&mut self, root: &Path) {
77 if let Some((sha, branch)) = crate::git::head(root) {
78 self.indexed_git_head = sha;
79 self.indexed_branch = branch;
80 }
81 }
82
83 pub fn touch_now(&mut self) {
84 self.last_indexed = SystemTime::now()
85 .duration_since(UNIX_EPOCH)
86 .map(|d| d.as_secs())
87 .unwrap_or(0);
88 }
89
90 pub fn alloc_segment(&mut self) -> u64 {
91 let id = self.next_segment_id;
92 self.next_segment_id += 1;
93 id
94 }
95}