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