VLink  2.0.0
A high-performance communication middleware
vdb_writer.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_writer.h
26  * @brief SQLite-backed recorder that produces @c .vdb / @c .vdbx bag files with batched WAL commits.
27  *
28  * @details
29  * @c VDBWriter materialises @c BagWriter on top of SQLite. Messages are accumulated in an
30  * in-memory cache and flushed to disk in WAL-mode transactions so that the write amplification
31  * remains bounded even at high publish rates; outstanding writes are committed during @c close()
32  * and an optional @c VACUUM step compacts the file on exit.
33  *
34  * @par VDB schema
35  *
36  * | Table | Purpose |
37  * | ----------- | ------------------------------------------------------------------- |
38  * | @c messages | (id, url_id, ts_us, action, data) -- one row per recorded message |
39  * | @c urls | (id, url, ser_type, schema_type) -- topic dictionary |
40  * | @c schemas | (id, ser_type, schema_type, blob) -- embedded schema descriptors |
41  * | @c metadata | (key, value) -- tag, machine name, vlink version, capture time |
42  * | @c stats | (url_id, count, bytes, loss) -- per-URL aggregates updated on flush |
43  *
44  * @par Writer states
45  * @code
46  * +----------+ on_begin() +---------+ push()/push_schema() +-----------+
47  * | closed | -----------------> | opening | -----------------------> | recording |
48  * +----------+ +---------+ +-----------+
49  * ^ |
50  * | v cache full / split
51  * | +------------+
52  * | | committing |
53  * | | WAL flush |
54  * | +------------+
55  * | |
56  * +-------------------- on_end() / dtor ----------------------- finalising
57  * |
58  * v
59  * (optional)
60  * vacuum
61  * @endcode
62  *
63  * @par Example
64  * @code
65  * vlink::BagWriter::Config cfg;
66  * cfg.compress = vlink::BagWriter::kCompressLzav;
67  * cfg.wal_mode = true;
68  *
69  * auto writer = vlink::BagWriter::create("/data/recording.vdb", cfg);
70  *
71  * writer->async_run();
72  *
73  * vlink::Frame frame;
74  * frame.timestamp = -1; // < 0 => writer auto-assigns from its clock (0 is recorded verbatim)
75  * frame.url = "dds://lidar/front";
76  * frame.ser_type = "demo.proto.PointCloud";
77  * frame.schema_type = vlink::SchemaType::kProtobuf;
78  * frame.action_type = vlink::ActionType::kPublish;
79  * frame.data = serialized_bytes;
80  * writer->push(frame);
81  * @endcode
82  *
83  * @see BagWriter, VCAPWriter
84  */
85 
86 #pragma once
87 
88 #include <memory>
89 #include <string>
90 
91 #include "./bag_writer.h"
92 
93 namespace vlink {
94 
95 /**
96  * @class VDBWriter
97  * @brief Concrete SQLite-backed @c BagWriter implementation with WAL caching and batch commits.
98  *
99  * @details
100  * Prefer @c BagWriter::create() for format-agnostic instantiation; instantiate this class
101  * directly only when a SQLite-specific feature is required.
102  */
103 class VLINK_EXPORT VDBWriter final : public BagWriter {
104  public:
105  /**
106  * @brief Opens or creates a SQLite bag file for recording.
107  *
108  * @param path Filesystem path of the @c .vdb or @c .vdbx target.
109  * @param config Recording configuration (split policy, compression, cache thresholds).
110  */
111  explicit VDBWriter(const std::string& path, const Config& config = {});
112 
113  /**
114  * @brief Commits any cached writes and closes the SQLite database.
115  */
116  ~VDBWriter() override;
117 
118  /**
119  * @brief Registers a callback invoked at each file-split boundary.
120  *
121  * @param callback Receives (split_index, filename) before or after the split.
122  * @param before @c true fires before the new file is opened; @c false fires after.
123  */
124  void register_split_callback(SplitCallback&& callback, bool before) override;
125 
126  /**
127  * @brief Registers a resolver that maps a serialisation-type string to @c SchemaData.
128  *
129  * @param callback Function consulted before inserting a URL row.
130  */
131  void register_schema_callback(SchemaCallback&& callback) override;
132 
133  /**
134  * @brief Embeds @p schema_data in the @c schemas table for offline introspection.
135  *
136  * @param schema_data Schema descriptor to embed.
137  * @param immediate @c true merges synchronously; @c false enqueues the write.
138  * @return @c false only when an immediate merge failed.
139  */
140  bool push_schema(const SchemaData& schema_data, bool immediate = false) override;
141 
142  /**
143  * @brief Returns the current value of the internal dumping flag.
144  *
145  * @return @c true while messages are actively being persisted.
146  */
147  [[nodiscard]] bool is_dumping() const override;
148 
149  /**
150  * @brief Reports whether split-file recording is active.
151  *
152  * @return @c true when emitting a @c .vdbx manifest with multiple parts.
153  */
154  [[nodiscard]] bool is_split_mode() const override;
155 
156  /**
157  * @brief Returns the index of the split part currently being written.
158  *
159  * @return Zero-based split index.
160  */
161  [[nodiscard]] int get_split_index() const override;
162 
163  protected:
164  int64_t record(const Frame& frame, bool immediate) override;
165 
166  int64_t get_record_timestamp() const override;
167 
168  size_t get_max_task_count() const override;
169 
170  void on_begin() override;
171 
172  void on_end() override;
173 
174  private:
175  void open(const std::string& path);
176 
177  void close();
178 
179  bool write(const std::string& url, const std::string& ser_type, SchemaType schema_type, ActionType action_type,
180  const Bytes& data, int64_t microseconds_timestamp);
181 
182  bool write_filex(bool complete = true);
183 
184  bool begin_cache();
185 
186  bool sync_cache();
187 
188  bool rollback_cache();
189 
190  bool merge_schema(SchemaData& schema_data);
191 
192  bool load_schema(const std::string& ser_type, SchemaType& schema_type, SchemaData& schema_data);
193 
194  bool insert_schema(const SchemaData& schema_data);
195 
196  struct Impl;
197  std::unique_ptr<Impl> impl_;
198 
200 };
201 
202 } // namespace vlink
Abstract VLink bag recorder with split, compression, schema embedding and a global hook.
#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