Skip to content

Commit 37be641

Browse files
committed
kill LogMsg storage, impl save store to disk
1 parent 93c1600 commit 37be641

File tree

10 files changed

+78
-356
lines changed

10 files changed

+78
-356
lines changed

crates/re_data_store/src/log_db.rs

+30-47
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::BTreeMap;
2+
13
use nohash_hasher::IntMap;
24

35
use re_arrow_store::{DataStoreConfig, TimeInt};
@@ -159,33 +161,31 @@ impl EntityDb {
159161
/// A in-memory database built from a stream of [`LogMsg`]es.
160162
#[derive(Default)]
161163
pub struct LogDb {
162-
/// Messages in the order they arrived
163-
chronological_row_ids: Vec<RowId>,
164-
log_messages: ahash::HashMap<RowId, LogMsg>,
165-
166-
/// Data that was logged with [`TimePoint::timeless`].
167-
/// We need to re-insert those in any new timelines
168-
/// that are created after they were logged.
169-
timeless_row_ids: Vec<RowId>,
164+
/// All [`EntityPathOpMsg`]s ever received.
165+
entity_op_msgs: BTreeMap<RowId, EntityPathOpMsg>,
170166

171167
/// Set by whomever created this [`LogDb`].
172168
pub data_source: Option<re_smart_channel::Source>,
173169

174170
/// Comes in a special message, [`LogMsg::BeginRecordingMsg`].
175-
recording_info: Option<RecordingInfo>,
171+
recording_msg: Option<BeginRecordingMsg>,
176172

177173
/// Where we store the entities.
178174
pub entity_db: EntityDb,
179175
}
180176

181177
impl LogDb {
178+
pub fn recording_msg(&self) -> Option<&BeginRecordingMsg> {
179+
self.recording_msg.as_ref()
180+
}
181+
182182
pub fn recording_info(&self) -> Option<&RecordingInfo> {
183-
self.recording_info.as_ref()
183+
self.recording_msg().map(|msg| &msg.info)
184184
}
185185

186186
pub fn recording_id(&self) -> RecordingId {
187-
if let Some(info) = &self.recording_info {
188-
info.recording_id
187+
if let Some(msg) = &self.recording_msg {
188+
msg.info.recording_id
189189
} else {
190190
RecordingId::ZERO
191191
}
@@ -203,11 +203,16 @@ impl LogDb {
203203
self.entity_db.tree.num_timeless_messages()
204204
}
205205

206+
pub fn len(&self) -> usize {
207+
self.entity_db.data_store.total_timeless_rows() as usize
208+
+ self.entity_db.data_store.total_temporal_rows() as usize
209+
}
210+
206211
pub fn is_empty(&self) -> bool {
207-
self.log_messages.is_empty()
212+
self.len() == 0
208213
}
209214

210-
pub fn add(&mut self, msg: LogMsg) -> Result<(), Error> {
215+
pub fn add(&mut self, msg: &LogMsg) -> Result<(), Error> {
211216
crate::profile_function!();
212217

213218
match &msg {
@@ -218,38 +223,27 @@ impl LogDb {
218223
time_point,
219224
path_op,
220225
} = msg;
226+
self.entity_op_msgs.insert(*row_id, msg.clone());
221227
self.entity_db.add_path_op(*row_id, time_point, path_op);
222228
}
223229
LogMsg::ArrowMsg(inner) => self.entity_db.try_add_arrow_msg(inner)?,
224230
LogMsg::Goodbye(_) => {}
225231
}
226232

227-
// TODO(#1619): the following only makes sense because, while we support sending and
228-
// receiving batches, we don't actually do so yet.
229-
// We need to stop storing raw `LogMsg`s before we can benefit from our batching.
230-
self.chronological_row_ids.push(msg.id());
231-
self.log_messages.insert(msg.id(), msg);
232-
233233
Ok(())
234234
}
235235

236236
fn add_begin_recording_msg(&mut self, msg: &BeginRecordingMsg) {
237-
self.recording_info = Some(msg.info.clone());
237+
self.recording_msg = Some(msg.clone());
238238
}
239239

240-
pub fn len(&self) -> usize {
241-
self.log_messages.len()
242-
}
243-
244-
/// In the order they arrived
245-
pub fn chronological_log_messages(&self) -> impl Iterator<Item = &LogMsg> {
246-
self.chronological_row_ids
247-
.iter()
248-
.filter_map(|id| self.get_log_msg(id))
240+
/// Returns an iterator over all [`EntityPathOpMsg`]s that have been written to this `LogDb`.
241+
pub fn iter_entity_op_msgs(&self) -> impl Iterator<Item = &EntityPathOpMsg> {
242+
self.entity_op_msgs.values()
249243
}
250244

251-
pub fn get_log_msg(&self, row_id: &RowId) -> Option<&LogMsg> {
252-
self.log_messages.get(row_id)
245+
pub fn get_entity_op_msg(&self, row_id: &RowId) -> Option<&EntityPathOpMsg> {
246+
self.entity_op_msgs.get(row_id)
253247
}
254248

255249
/// Free up some RAM by forgetting the older parts of all timelines.
@@ -263,26 +257,15 @@ impl LogDb {
263257
let cutoff_times = self.entity_db.data_store.oldest_time_per_timeline();
264258

265259
let Self {
266-
chronological_row_ids,
267-
log_messages,
268-
timeless_row_ids,
260+
entity_op_msgs,
269261
data_source: _,
270-
recording_info: _,
262+
recording_msg: _,
271263
entity_db,
272264
} = self;
273265

274266
{
275-
crate::profile_scope!("chronological_row_ids");
276-
chronological_row_ids.retain(|row_id| !drop_row_ids.contains(row_id));
277-
}
278-
279-
{
280-
crate::profile_scope!("log_messages");
281-
log_messages.retain(|row_id, _| !drop_row_ids.contains(row_id));
282-
}
283-
{
284-
crate::profile_scope!("timeless_row_ids");
285-
timeless_row_ids.retain(|row_id| !drop_row_ids.contains(row_id));
267+
crate::profile_scope!("entity_op_msgs");
268+
entity_op_msgs.retain(|row_id, _| !drop_row_ids.contains(row_id));
286269
}
287270

288271
entity_db.purge(&cutoff_times, &drop_row_ids);

crates/re_log_types/src/encoding.rs

+11
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ mod encoder {
107107
}
108108
encoder.finish()
109109
}
110+
111+
pub fn encode_owned(
112+
messages: impl Iterator<Item = LogMsg>,
113+
write: impl std::io::Write,
114+
) -> Result<(), EncodeError> {
115+
let mut encoder = Encoder::new(write)?;
116+
for message in messages {
117+
encoder.append(&message)?;
118+
}
119+
encoder.finish()
120+
}
110121
}
111122

112123
#[cfg(feature = "save")]

crates/re_log_types/src/lib.rs

-14
Original file line numberDiff line numberDiff line change
@@ -187,20 +187,6 @@ pub enum LogMsg {
187187
Goodbye(RowId),
188188
}
189189

190-
impl LogMsg {
191-
pub fn id(&self) -> RowId {
192-
match self {
193-
Self::BeginRecordingMsg(msg) => msg.row_id,
194-
Self::EntityPathOpMsg(msg) => msg.row_id,
195-
Self::Goodbye(row_id) => *row_id,
196-
// TODO(#1619): the following only makes sense because, while we support sending and
197-
// receiving batches, we don't actually do so yet.
198-
// We need to stop storing raw `LogMsg`s before we can benefit from our batching.
199-
Self::ArrowMsg(msg) => msg.table_id.into_row_id(),
200-
}
201-
}
202-
}
203-
204190
impl_into_enum!(BeginRecordingMsg, LogMsg, BeginRecordingMsg);
205191
impl_into_enum!(EntityPathOpMsg, LogMsg, EntityPathOpMsg);
206192
impl_into_enum!(ArrowMsg, LogMsg, ArrowMsg);

crates/re_viewer/src/app.rs

+33-57
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ impl App {
695695
log_db.data_source = Some(self.rx.source().clone());
696696
}
697697

698-
if let Err(err) = log_db.add(msg) {
698+
if let Err(err) = log_db.add(&msg) {
699699
re_log::error!("Failed to add incoming msg: {err}");
700700
};
701701

@@ -906,8 +906,6 @@ fn preview_files_being_dropped(egui_ctx: &egui::Context) {
906906
enum PanelSelection {
907907
#[default]
908908
Viewport,
909-
910-
EventLog,
911909
}
912910

913911
#[derive(Default, serde::Deserialize, serde::Serialize)]
@@ -930,8 +928,6 @@ struct AppState {
930928
/// Which view panel is currently being shown
931929
panel_selection: PanelSelection,
932930

933-
event_log_view: crate::event_log_view::EventLogView,
934-
935931
selection_panel: crate::selection_panel::SelectionPanel,
936932
time_panel: crate::time_panel::TimePanel,
937933

@@ -959,7 +955,6 @@ impl AppState {
959955
selected_rec_id,
960956
recording_configs,
961957
panel_selection,
962-
event_log_view,
963958
blueprints,
964959
selection_panel,
965960
time_panel,
@@ -1004,7 +999,6 @@ impl AppState {
1004999
.entry(selected_app_id)
10051000
.or_insert_with(|| Blueprint::new(ui.ctx()))
10061001
.blueprint_panel_and_viewport(&mut ctx, ui),
1007-
PanelSelection::EventLog => event_log_view.ui(&mut ctx, ui),
10081002
});
10091003

10101004
// move time last, so we get to see the first data first!
@@ -1536,16 +1530,6 @@ fn main_view_selector_ui(ui: &mut egui::Ui, app: &mut App) {
15361530
{
15371531
ui.close_menu();
15381532
}
1539-
if ui
1540-
.selectable_value(
1541-
&mut app.state.panel_selection,
1542-
PanelSelection::EventLog,
1543-
"Event Log",
1544-
)
1545-
.clicked()
1546-
{
1547-
ui.close_menu();
1548-
}
15491533
});
15501534
}
15511535
}
@@ -1751,44 +1735,36 @@ fn save_database_to_file(
17511735
path: std::path::PathBuf,
17521736
time_selection: Option<(re_data_store::Timeline, TimeRangeF)>,
17531737
) -> impl FnOnce() -> anyhow::Result<std::path::PathBuf> {
1754-
use re_log_types::{EntityPathOpMsg, TimeInt};
1755-
1756-
let msgs = match time_selection {
1757-
// Fast path: no query, just dump everything.
1758-
None => log_db
1759-
.chronological_log_messages()
1760-
.cloned()
1761-
.collect::<Vec<_>>(),
1762-
1763-
// Query path: time to filter!
1764-
Some((timeline, range)) => {
1765-
use std::ops::RangeInclusive;
1766-
let range: RangeInclusive<TimeInt> = range.min.floor()..=range.max.ceil();
1767-
log_db
1768-
.chronological_log_messages()
1769-
.filter(|msg| {
1770-
match msg {
1771-
LogMsg::BeginRecordingMsg(_) | LogMsg::Goodbye(_) => {
1772-
true // timeless
1773-
}
1774-
LogMsg::EntityPathOpMsg(EntityPathOpMsg { time_point, .. }) => {
1775-
time_point.is_timeless() || {
1776-
let is_within_range = time_point
1777-
.get(&timeline)
1778-
.map_or(false, |t| range.contains(t));
1779-
is_within_range
1780-
}
1781-
}
1782-
LogMsg::ArrowMsg(_) => {
1783-
// TODO(john)
1784-
false
1785-
}
1786-
}
1787-
})
1788-
.cloned()
1789-
.collect::<Vec<_>>()
1790-
}
1791-
};
1738+
use re_arrow_store::TimeRange;
1739+
1740+
crate::profile_scope!("dump_messages");
1741+
1742+
let begin_rec_msg = log_db
1743+
.recording_msg()
1744+
.map(|msg| LogMsg::BeginRecordingMsg(msg.clone()));
1745+
1746+
let ent_op_msgs = log_db
1747+
.iter_entity_op_msgs()
1748+
.map(|msg| LogMsg::EntityPathOpMsg(msg.clone()))
1749+
.collect_vec();
1750+
1751+
let time_filter = time_selection.map(|(timeline, range)| {
1752+
(
1753+
timeline,
1754+
TimeRange::new(range.min.floor(), range.max.ceil()),
1755+
)
1756+
});
1757+
let data_msgs = log_db
1758+
.entity_db
1759+
.data_store
1760+
.to_data_tables(time_filter)
1761+
.map(|table| LogMsg::ArrowMsg(table.to_arrow_msg().unwrap()))
1762+
.collect_vec();
1763+
1764+
let msgs = std::iter::once(begin_rec_msg)
1765+
.flatten()
1766+
.chain(ent_op_msgs)
1767+
.chain(data_msgs);
17921768

17931769
move || {
17941770
crate::profile_scope!("save_to_file");
@@ -1797,7 +1773,7 @@ fn save_database_to_file(
17971773
let file = std::fs::File::create(path.as_path())
17981774
.with_context(|| format!("Failed to create file at {path:?}"))?;
17991775

1800-
re_log_types::encoding::encode(msgs.iter(), file)
1776+
re_log_types::encoding::encode_owned(msgs, file)
18011777
.map(|_| path)
18021778
.context("Message encode")
18031779
}
@@ -1811,7 +1787,7 @@ fn load_rrd_to_log_db(mut read: impl std::io::Read) -> anyhow::Result<LogDb> {
18111787

18121788
let mut log_db = LogDb::default();
18131789
for msg in decoder {
1814-
log_db.add(msg?)?;
1790+
log_db.add(&msg?)?;
18151791
}
18161792
Ok(log_db)
18171793
}

crates/re_viewer/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod viewer_analytics;
1414

1515
pub(crate) use misc::{mesh_loader, Item, TimeControl, TimeView, ViewerContext};
1616
use re_log_types::PythonVersion;
17-
pub(crate) use ui::{event_log_view, memory_panel, selection_panel, time_panel, UiVerbosity};
17+
pub(crate) use ui::{memory_panel, selection_panel, time_panel, UiVerbosity};
1818

1919
pub use app::{App, StartupOptions};
2020
pub use remote_viewer_app::RemoteViewerApp;

crates/re_viewer/src/misc/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl Item {
3838
Item::InstancePath(space_view_id, _) => space_view_id
3939
.map(|space_view_id| blueprint.viewport.space_view(&space_view_id).is_some())
4040
.unwrap_or(true),
41-
Item::RowId(row_id) => log_db.get_log_msg(row_id).is_some(),
41+
Item::RowId(row_id) => log_db.get_entity_op_msg(row_id).is_some(),
4242
Item::SpaceView(space_view_id) => {
4343
blueprint.viewport.space_view(space_view_id).is_some()
4444
}

crates/re_viewer/src/ui/data_ui/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub enum UiVerbosity {
2525
Small,
2626

2727
/// At most this height
28+
#[allow(dead_code)]
2829
MaxHeight(f32),
2930

3031
/// Display a reduced set, used for hovering.

crates/re_viewer/src/ui/data_ui/row_id.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl DataUi for RowId {
1717
ctx.row_id_button(ui, *self);
1818
}
1919
UiVerbosity::All | UiVerbosity::Reduced => {
20-
if let Some(msg) = ctx.log_db.get_log_msg(self) {
20+
if let Some(msg) = ctx.log_db.get_entity_op_msg(self) {
2121
msg.data_ui(ctx, ui, verbosity, query);
2222
} else {
2323
ctx.row_id_button(ui, *self);

0 commit comments

Comments
 (0)