Skip to content

Commit 98c18b3

Browse files
chinmaygardednfield
authored andcommitted
Import the archivist framework.
1 parent d3626cd commit 98c18b3

16 files changed

+1606
-0
lines changed

impeller/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ config("impeller_public_config") {
99
group("impeller") {
1010
public_deps = [
1111
"aiks",
12+
"archivist",
1213
"base",
1314
"compiler",
1415
"display_list",
@@ -24,6 +25,7 @@ executable("impeller_unittests") {
2425

2526
deps = [
2627
"aiks:aiks_unittests",
28+
"archivist:archivist_unittests",
2729
"base:base_unittests",
2830
"compiler:compiler_unittests",
2931
"display_list:display_list_unittests",

impeller/archivist/BUILD.gn

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2013 The Flutter Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
import("../tools/impeller.gni")
6+
7+
impeller_component("archivist") {
8+
# Only the umbrella header is public since all other TU's are implementation
9+
# detail that will be compiled away in release modes.
10+
# Because they are implementation details, they may expose dependency headers.
11+
public = [ "archive.h" ]
12+
13+
sources = [
14+
"archive.cc",
15+
"archive_class_registration.cc",
16+
"archive_class_registration.h",
17+
"archive_database.cc",
18+
"archive_database.h",
19+
"archive_statement.cc",
20+
"archive_statement.h",
21+
"archive_transaction.cc",
22+
"archive_transaction.h",
23+
"archive_vector.cc",
24+
"archive_vector.h",
25+
]
26+
27+
public_deps = [ "../base" ]
28+
29+
deps = [ "//third_party/sqlite" ]
30+
}
31+
32+
impeller_component("archivist_unittests") {
33+
testonly = true
34+
sources = [ "archivist_unittests.cc" ]
35+
deps = [
36+
":archivist",
37+
"//flutter/testing",
38+
]
39+
}

impeller/archivist/archive.cc

+317
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "impeller/archivist/archive.h"
6+
7+
#include <iterator>
8+
9+
#include "flutter/fml/logging.h"
10+
#include "impeller/archivist/archive_class_registration.h"
11+
#include "impeller/archivist/archive_database.h"
12+
#include "impeller/archivist/archive_statement.h"
13+
#include "impeller/archivist/archive_vector.h"
14+
15+
namespace impeller {
16+
17+
Archive::Archive(const std::string& path, bool recreate)
18+
: _db(std::make_unique<ArchiveDatabase>(path, recreate)) {}
19+
20+
Archive::~Archive() {
21+
FML_DCHECK(_transactionCount == 0) << "There must be no pending transactions";
22+
}
23+
24+
bool Archive::isReady() const {
25+
return _db->isReady();
26+
}
27+
28+
bool Archive::archiveInstance(const ArchiveDef& definition,
29+
const ArchiveSerializable& archivable,
30+
int64_t& lastInsertIDOut) {
31+
if (!isReady()) {
32+
return false;
33+
}
34+
35+
auto transaction = _db->acquireTransaction(_transactionCount);
36+
37+
const auto* registration = _db->registrationForDefinition(definition);
38+
39+
if (registration == nullptr) {
40+
return false;
41+
}
42+
43+
auto statement = registration->insertStatement();
44+
45+
if (!statement.isReady() || !statement.reset()) {
46+
/*
47+
* Must be able to reset the statement for a new write
48+
*/
49+
return false;
50+
}
51+
52+
auto itemName = archivable.archiveName();
53+
54+
/*
55+
* The lifecycle of the archive item is tied to this scope and there is no
56+
* way for the user to create an instance of an archive item. So its safe
57+
* for its members to be references. It does not manage the lifetimes of
58+
* anything.
59+
*/
60+
ArchiveItem item(*this, statement, *registration, itemName);
61+
62+
/*
63+
* We need to bind the primary key only if the item does not provide its own
64+
*/
65+
if (!definition.autoAssignName &&
66+
!statement.bind(ArchiveClassRegistration::NameIndex, itemName)) {
67+
return false;
68+
}
69+
70+
if (!archivable.serialize(item)) {
71+
return false;
72+
}
73+
74+
if (statement.run() != ArchiveStatement::Result::Done) {
75+
return false;
76+
}
77+
78+
int64_t lastInsert = _db->lastInsertRowID();
79+
80+
if (!definition.autoAssignName &&
81+
lastInsert != static_cast<int64_t>(itemName)) {
82+
return false;
83+
}
84+
85+
lastInsertIDOut = lastInsert;
86+
87+
/*
88+
* If any of the nested calls fail, we would have already checked for the
89+
* failure and returned.
90+
*/
91+
transaction.markWritesSuccessful();
92+
93+
return true;
94+
}
95+
96+
bool Archive::unarchiveInstance(const ArchiveDef& definition,
97+
ArchiveSerializable::ArchiveName name,
98+
ArchiveSerializable& archivable) {
99+
UnarchiveStep stepper = [&archivable](ArchiveItem& item) {
100+
archivable.deserialize(item);
101+
return false /* no-more after single read */;
102+
};
103+
104+
return unarchiveInstances(definition, stepper, name) == 1;
105+
}
106+
107+
size_t Archive::unarchiveInstances(const ArchiveDef& definition,
108+
Archive::UnarchiveStep stepper,
109+
ArchiveSerializable::ArchiveName name) {
110+
if (!isReady()) {
111+
return 0;
112+
}
113+
114+
const auto* registration = _db->registrationForDefinition(definition);
115+
116+
if (registration == nullptr) {
117+
return 0;
118+
}
119+
120+
const bool isQueryingSingle = name != ArchiveNameAuto;
121+
122+
auto statement = registration->queryStatement(isQueryingSingle);
123+
124+
if (!statement.isReady() || !statement.reset()) {
125+
return 0;
126+
}
127+
128+
if (isQueryingSingle) {
129+
/*
130+
* If a single statement is being queried for, bind the name as a statement
131+
* argument.
132+
*/
133+
if (!statement.bind(ArchiveClassRegistration::NameIndex, name)) {
134+
return 0;
135+
}
136+
}
137+
138+
if (statement.columnCount() !=
139+
registration->memberCount() + 1 /* primary key */) {
140+
return 0;
141+
}
142+
143+
/*
144+
* Acquire a transaction but never mark it successful since we will never
145+
* be committing any writes to the database during unarchiving.
146+
*/
147+
auto transaction = _db->acquireTransaction(_transactionCount);
148+
149+
size_t itemsRead = 0;
150+
151+
while (statement.run() == ArchiveStatement::Result::Row) {
152+
itemsRead++;
153+
154+
/*
155+
* Prepare a fresh archive item for the given statement
156+
*/
157+
ArchiveItem item(*this, statement, *registration, name);
158+
159+
if (!stepper(item)) {
160+
break;
161+
}
162+
163+
if (isQueryingSingle) {
164+
break;
165+
}
166+
}
167+
168+
return itemsRead;
169+
}
170+
171+
ArchiveItem::ArchiveItem(Archive& context,
172+
ArchiveStatement& statement,
173+
const ArchiveClassRegistration& registration,
174+
ArchiveSerializable::ArchiveName name)
175+
: _context(context),
176+
_statement(statement),
177+
_registration(registration),
178+
_name(name),
179+
_currentClass(registration.className()) {}
180+
181+
ArchiveSerializable::ArchiveName ArchiveItem::name() const {
182+
return _name;
183+
}
184+
185+
bool ArchiveItem::encode(ArchiveSerializable::Member member,
186+
const std::string& item) {
187+
auto found = _registration.findColumn(_currentClass, member);
188+
return found.second ? _statement.bind(found.first, item) : false;
189+
}
190+
191+
bool ArchiveItem::encodeIntegral(ArchiveSerializable::Member member,
192+
int64_t item) {
193+
auto found = _registration.findColumn(_currentClass, member);
194+
return found.second ? _statement.bind(found.first, item) : false;
195+
}
196+
197+
bool ArchiveItem::encode(ArchiveSerializable::Member member, double item) {
198+
auto found = _registration.findColumn(_currentClass, member);
199+
return found.second ? _statement.bind(found.first, item) : false;
200+
}
201+
202+
bool ArchiveItem::encode(ArchiveSerializable::Member member,
203+
const Allocation& item) {
204+
auto found = _registration.findColumn(_currentClass, member);
205+
return found.second ? _statement.bind(found.first, item) : false;
206+
}
207+
208+
bool ArchiveItem::encode(ArchiveSerializable::Member member,
209+
const ArchiveDef& otherDef,
210+
const ArchiveSerializable& other) {
211+
auto found = _registration.findColumn(_currentClass, member);
212+
213+
if (!found.second) {
214+
return false;
215+
}
216+
217+
/*
218+
* We need to fully archive the other instance first because it could
219+
* have a name that is auto assigned. In that case, we cannot ask it before
220+
* archival (via `other.archiveName()`).
221+
*/
222+
int64_t lastInsert = 0;
223+
if (!_context.archiveInstance(otherDef, other, lastInsert)) {
224+
return false;
225+
}
226+
227+
/*
228+
* Bind the name of the serialiable
229+
*/
230+
if (!_statement.bind(found.first, lastInsert)) {
231+
return false;
232+
}
233+
234+
return true;
235+
}
236+
237+
std::pair<bool, int64_t> ArchiveItem::encodeVectorKeys(
238+
std::vector<int64_t>&& members) {
239+
ArchiveVector vector(std::move(members));
240+
int64_t vectorID = 0;
241+
if (!_context.archiveInstance(ArchiveVector::ArchiveDefinition, //
242+
vector, //
243+
vectorID)) {
244+
return {false, 0};
245+
}
246+
return {true, vectorID};
247+
}
248+
249+
bool ArchiveItem::decodeVectorKeys(ArchiveSerializable::ArchiveName name,
250+
std::vector<int64_t>& members) {
251+
ArchiveVector vector;
252+
253+
if (!_context.unarchiveInstance(ArchiveVector::ArchiveDefinition, name,
254+
vector)) {
255+
return false;
256+
}
257+
258+
const auto& keys = vector.keys();
259+
260+
std::move(keys.begin(), keys.end(), std::back_inserter(members));
261+
262+
return true;
263+
}
264+
265+
bool ArchiveItem::decode(ArchiveSerializable::Member member,
266+
std::string& item) {
267+
auto found = _registration.findColumn(_currentClass, member);
268+
return found.second ? _statement.column(found.first, item) : false;
269+
}
270+
271+
bool ArchiveItem::decodeIntegral(ArchiveSerializable::Member member,
272+
int64_t& item) {
273+
auto found = _registration.findColumn(_currentClass, member);
274+
return found.second ? _statement.column(found.first, item) : false;
275+
}
276+
277+
bool ArchiveItem::decode(ArchiveSerializable::Member member, double& item) {
278+
auto found = _registration.findColumn(_currentClass, member);
279+
return found.second ? _statement.column(found.first, item) : false;
280+
}
281+
282+
bool ArchiveItem::decode(ArchiveSerializable::Member member, Allocation& item) {
283+
auto found = _registration.findColumn(_currentClass, member);
284+
return found.second ? _statement.column(found.first, item) : false;
285+
}
286+
287+
bool ArchiveItem::decode(ArchiveSerializable::Member member,
288+
const ArchiveDef& otherDef,
289+
ArchiveSerializable& other) {
290+
auto found = _registration.findColumn(_currentClass, member);
291+
292+
/*
293+
* Make sure a member is present at that column
294+
*/
295+
if (!found.second) {
296+
return false;
297+
}
298+
299+
/*
300+
* Try to find the foreign key in the current items row
301+
*/
302+
int64_t foreignKey = 0;
303+
if (!_statement.column(found.first, foreignKey)) {
304+
return false;
305+
}
306+
307+
/*
308+
* Find the other item and unarchive by this foreign key
309+
*/
310+
if (!_context.unarchiveInstance(otherDef, foreignKey, other)) {
311+
return false;
312+
}
313+
314+
return true;
315+
}
316+
317+
} // namespace impeller

0 commit comments

Comments
 (0)