VLink  2.0.0
A high-performance communication middleware
vdb_reader.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file vdb_reader.h
26  * @brief SQLite-backed playback for VLink @c .vdb / @c .vdbx bag files.
27  *
28  * @details
29  * @c VDBReader is the concrete @c BagReader implementation for the SQLite container that VLink
30  * uses for recordings that require true random-access indexing, in-place repair, and tag-based
31  * navigation. Splits are described by a @c .vdbx JSON manifest pointing at one or more sibling
32  * @c .vdb files; this reader follows the manifest transparently.
33  *
34  * @par VDB schema
35  *
36  * | Table | Key columns | Purpose |
37  * | ----------------- | -------------------------------------- | ---------------------------------------- |
38  * | @c messages | id, url_id, ts_us, action, data | recorded payloads ordered by timestamp |
39  * | @c urls | id, url, ser_type, schema_type | per-topic identity dictionary |
40  * | @c schemas | id, ser_type, schema_type, blob | embedded schema descriptors |
41  * | @c metadata | key, value | tag name, version, capture machine, etc. |
42  * | @c stats | url_id, count, bytes, loss | per-URL aggregate counters |
43  * | @c index | ts_us, message_id | timestamp -> message random-access index |
44  *
45  * @par Reader states
46  * @code
47  * +---------+ play() +---------+ pause() +---------+
48  * | stopped | ---------------> | playing | ---------------> | paused |
49  * +---------+ +---------+ +---------+
50  * ^ | ^ |
51  * | | | resume() / pause_to_next()|
52  * +--- stop() / EOF -----------+ +--------------------------+
53  * |
54  * | jump(time, rate, times)
55  * v
56  * +---------+
57  * | seeking | SQL index lookup
58  * +---------+
59  * @endcode
60  *
61  * @par Example
62  * @code
63  * auto reader = vlink::BagReader::create("/data/recording.vdb");
64  *
65  * reader->register_output_callback([](const vlink::Frame& frame) {
66  * dispatch(frame.url, frame.data);
67  * });
68  *
69  * reader->async_run();
70  * reader->play({});
71  * @endcode
72  *
73  * @see BagReader, VCAPReader
74  */
75 
76 #pragma once
77 
78 #include <future>
79 #include <memory>
80 #include <string>
81 #include <vector>
82 
83 #include "./bag_reader.h"
84 
85 namespace vlink {
86 
87 /**
88  * @class VDBReader
89  * @brief Concrete SQLite-backed @c BagReader implementation with full random-access support.
90  *
91  * @details
92  * Prefer @c BagReader::create() for format-agnostic instantiation; instantiate this class
93  * directly only when a SQLite-specific feature is required.
94  */
95 class VLINK_EXPORT VDBReader final : public BagReader {
96  public:
97  /**
98  * @brief Opens a SQLite bag file for playback.
99  *
100  * @param path Filesystem path of the @c .vdb or @c .vdbx file.
101  * @param read_only @c true opens the database without write capability (default).
102  * @param try_to_fix Reserved hook for table-rebuild recovery when table checks are enabled.
103  */
104  explicit VDBReader(const std::string& path, bool read_only = true, bool try_to_fix = false);
105 
106  /**
107  * @brief Stops playback and closes the SQLite database handle.
108  */
109  ~VDBReader() override;
110 
111  /**
112  * @brief Attaches a @c BagPluginInterface for custom URL or type rewriting.
113  *
114  * @param plugin_interface Plugin instance; pass @c nullptr to detach.
115  */
116  void bind_plugin_interface(const std::shared_ptr<BagPluginInterface>& plugin_interface) override;
117 
118  /**
119  * @brief Registers a callback invoked on every playback state transition.
120  *
121  * @param status_callback Receives the new @c Status value.
122  */
123  void register_status_callback(StatusCallback&& status_callback) override;
124 
125  /**
126  * @brief Registers a callback fired once the database is open and parsed.
127  *
128  * @param ready_callback Invoked when the reader transitions out of opening state.
129  */
130  void register_ready_callback(ReadyCallback&& ready_callback) override;
131 
132  /**
133  * @brief Registers a callback fired when playback ends naturally or is interrupted.
134  *
135  * @param finish_callback Receives a flag indicating whether playback was interrupted.
136  */
137  void register_finish_callback(FinishCallback&& finish_callback) override;
138 
139  /**
140  * @brief Registers the message-delivery callback consumed during playback.
141  *
142  * @param output_callback Invoked for each replayed message.
143  */
144  void register_output_callback(OutputCallback&& output_callback) override;
145 
146  /**
147  * @brief Starts playback with the given configuration.
148  *
149  * @param config Playback configuration (start / end times, rate, filters, loop count).
150  */
151  void play(const Config& config) override;
152 
153  /**
154  * @brief Stops playback and rewinds to the recording start.
155  */
156  void stop() override;
157 
158  /**
159  * @brief Pauses playback at the current position.
160  */
161  void pause() override;
162 
163  /**
164  * @brief Resumes paused playback from the current position.
165  */
166  void resume() override;
167 
168  /**
169  * @brief Emits one more message and then pauses again.
170  */
171  void pause_to_next() override;
172 
173  /**
174  * @brief Seeks to @p begin_time and resumes playback at the new position.
175  *
176  * @param begin_time Target timestamp in milliseconds, relative to recording start.
177  * @param rate Playback rate multiplier applied after the seek.
178  * @param times Number of loop iterations after the jump.
179  * @param force_to_play @c true forces play state even if currently paused.
180  */
181  void jump(int64_t begin_time, double rate, int times, bool force_to_play = false) override;
182 
183  /**
184  * @brief Verifies the integrity of the SQLite bag file asynchronously.
185  *
186  * @return Future resolving to @c true when the file passes the integrity check.
187  */
188  std::future<bool> check() override;
189 
190  /**
191  * @brief Rebuilds the SQLite index tables asynchronously.
192  *
193  * @return Future resolving to @c true on success.
194  */
195  std::future<bool> reindex() override;
196 
197  /**
198  * @brief Repairs a corrupt SQLite bag file asynchronously.
199  *
200  * @param rebuild @c true rebuilds the entire index from scratch.
201  * @return Future resolving to @c true on success.
202  */
203  std::future<bool> fix(bool rebuild = false) override;
204 
205  /**
206  * @brief Updates the tag column in the @c metadata table.
207  *
208  * @param tag_name New tag string.
209  */
210  void tag(const std::string& tag_name) override;
211 
212  /**
213  * @brief Returns the current playback cursor in milliseconds.
214  *
215  * @return Position relative to the recording start.
216  */
217  [[nodiscard]] int64_t get_timestamp() const override;
218 
219  /**
220  * @brief Returns the timestamp of the last delivered message.
221  *
222  * @return Last data timestamp in milliseconds, or @c 0 when stopped.
223  */
224  [[nodiscard]] int64_t get_real_timestamp() const override;
225 
226  /**
227  * @brief Returns the playback status.
228  *
229  * @return One of @c kStopped, @c kPaused, or @c kPlaying.
230  */
231  [[nodiscard]] Status get_status() const override;
232 
233  /**
234  * @brief Returns the bag metadata populated when the file was opened.
235  *
236  * @return Const reference to the @c Info struct.
237  */
238  [[nodiscard]] const Info& get_info() const override;
239 
240  /**
241  * @brief Enumerates every schema embedded in the @c schemas table.
242  *
243  * @return Vector of @c SchemaData descriptors.
244  */
245  [[nodiscard]] std::vector<SchemaData> detect_schema() override;
246 
247  /**
248  * @brief Reports whether the bag is split across multiple @c .vdb files.
249  *
250  * @return @c true when reading a @c .vdbx manifest with multiple parts.
251  */
252  [[nodiscard]] bool is_split_mode() const override;
253 
254  /**
255  * @brief Returns the index of the split part currently under playback.
256  *
257  * @return Zero-based split index.
258  */
259  [[nodiscard]] int get_split_index() const override;
260 
261  /**
262  * @brief Reports whether a @c jump() seek is currently being processed.
263  *
264  * @return @c true while a seek is in flight.
265  */
266  [[nodiscard]] bool is_jumping() const override;
267 
268  protected:
269  size_t get_max_task_count() const override;
270 
271  void on_begin() override;
272 
273  void on_end() override;
274 
275  bool do_open_cursor(const Config& config) override;
276 
277  bool do_read_next(Frame& out, bool& is_error) override;
278 
279  private:
280  bool prepare_cursor_stmt(int file_index);
281 
282  void update_status(Status status);
283 
284  void do_stop();
285 
286  void do_pause();
287 
288  bool prepare_file(void* file);
289 
290  void open(const std::string& path);
291 
292  void close();
293 
294  int get_reset_index(const Config& config);
295 
296  void read(const Config& config);
297 
298  struct Impl;
299  std::unique_ptr<Impl> impl_;
300 
302 };
303 
304 } // namespace vlink
Abstract player for VLink bag recordings with seek, loop and rate control.
#define VLINK_EXPORT
Definition: macros.h:81
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174