vole_document/field/
session.rs1use std::path::Path;
6
7#[cfg(not(feature = "entropyfs-store"))]
8use crate::error::Error;
9use crate::error::Result;
10use crate::limits::Limits;
11use crate::store::IoSnapshot;
12
13use super::index::FsIndexStore;
14use super::observe::{
15 ModelMemo, ObserveRequest, ObserveStats, observe_session, open_session_index,
16};
17use super::promote::PromotePolicy;
18use super::provenance::FieldAnswer;
19use super::{Field, FieldId, FieldStore};
20
21pub const DEFAULT_MODEL_MEMO_BYTES: u64 = 64 * 1024 * 1024;
23
24#[derive(Debug, Clone, Copy)]
26pub struct SessionOptions {
27 pub entropyfs: bool,
29 pub packed: bool,
32 pub model_memo_bytes: u64,
34 pub promote: PromotePolicy,
36}
37
38impl Default for SessionOptions {
39 fn default() -> Self {
40 SessionOptions {
41 entropyfs: false,
42 packed: false,
43 model_memo_bytes: DEFAULT_MODEL_MEMO_BYTES,
44 promote: PromotePolicy::default(),
45 }
46 }
47}
48
49pub struct DocumentFieldSession {
59 store: FieldStore,
60 field: Field,
61 field_id: FieldId,
62 index: FsIndexStore,
65 models: ModelMemo,
66 pending_open_io: Option<IoSnapshot>,
69}
70
71impl DocumentFieldSession {
72 pub fn open(store_dir: &Path, field_hex: &str, opts: SessionOptions) -> Result<Self> {
76 let prof = super::warm_prof_enabled();
77 let t0 = std::time::Instant::now();
78 let mut store = if opts.packed {
79 FieldStore::open_packed(store_dir)?
80 } else if opts.entropyfs {
81 #[cfg(feature = "entropyfs-store")]
82 {
83 FieldStore::open_entropyfs(store_dir)?
84 }
85 #[cfg(not(feature = "entropyfs-store"))]
86 {
87 return Err(Error::unsupported_feature(
88 "--entropyfs requires a build with the entropyfs-store feature",
89 ));
90 }
91 } else {
92 FieldStore::open(store_dir)?
93 };
94 store.set_promote(opts.promote);
95 let t_store = t0.elapsed();
96 let field_id = FieldId::from_hex(field_hex)?;
97 let field = Field::open(&store, &field_id, Limits::DEFAULT)?;
98 let open_io = field.open_io();
99 let t_field = t0.elapsed();
100 let index = open_session_index(&store)?;
102 let t_index = t0.elapsed();
103 if prof {
104 eprintln!(
105 "[vole-profile] store_open_us={} field_open_us={} index_open_us={} session_open_total_us={}",
106 t_store.as_micros(),
107 t_field.as_micros().saturating_sub(t_store.as_micros()),
108 t_index.as_micros().saturating_sub(t_field.as_micros()),
109 t_index.as_micros()
110 );
111 }
112 Ok(Self {
113 store,
114 field,
115 field_id,
116 index,
117 models: ModelMemo::with_budget(opts.model_memo_bytes),
118 pending_open_io: Some(open_io),
119 })
120 }
121
122 pub fn field_id(&self) -> FieldId {
124 self.field_id
125 }
126
127 pub fn observe(
130 &mut self,
131 req: &ObserveRequest,
132 limits: Limits,
133 ) -> Result<(FieldAnswer, ObserveStats, FieldId)> {
134 let open_io = self.pending_open_io.take().unwrap_or_default();
135 observe_session(
136 &mut self.store,
137 &self.field,
138 &self.index,
139 open_io,
140 req,
141 limits,
142 self.models.clone(),
143 )
144 }
145
146 pub fn observe_batch(
148 &mut self,
149 reqs: &[ObserveRequest],
150 limits: Limits,
151 ) -> Vec<Result<(FieldAnswer, ObserveStats, FieldId)>> {
152 reqs.iter().map(|r| self.observe(r, limits)).collect()
153 }
154
155 pub fn sync(&self) -> Result<()> {
157 self.store.sync()
158 }
159}