1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #include "storage/cache/storage_cache_binlog_reader.h"
8 
9 namespace Storage {
10 namespace Cache {
11 namespace details {
12 
BinlogWrapper(File & binlog,const Settings & settings,int64 till)13 BinlogWrapper::BinlogWrapper(
14 	File &binlog,
15 	const Settings &settings,
16 	int64 till)
17 : _binlog(binlog)
18 , _settings(settings)
19 , _till(till ? till : _binlog.size())
20 , _data(_settings.readBlockSize)
21 , _full(_data) {
22 }
23 
finished() const24 bool BinlogWrapper::finished() const {
25 	return _finished;
26 }
27 
failed() const28 bool BinlogWrapper::failed() const {
29 	return _failed;
30 }
31 
ReadHeader(File & binlog,const Settings & settings)32 std::optional<BasicHeader> BinlogWrapper::ReadHeader(
33 		File &binlog,
34 		const Settings &settings) {
35 	auto result = BasicHeader();
36 	if (binlog.offset() != 0) {
37 		return {};
38 	} else if (binlog.read(bytes::object_as_span(&result)) != sizeof(result)) {
39 		return {};
40 	} else if (result.getFormat() != Format::Format_0) {
41 		return {};
42 	} else if (settings.trackEstimatedTime
43 		!= !!(result.flags & result.kTrackEstimatedTime)) {
44 		return {};
45 	}
46 	return result;
47 }
48 
readPart()49 bool BinlogWrapper::readPart() {
50 	if (_finished) {
51 		return false;
52 	}
53 	const auto no = [&] {
54 		finish();
55 		return false;
56 	};
57 	const auto offset = _binlog.offset();
58 	const auto left = (_till - offset);
59 	if (!left) {
60 		return no();
61 	}
62 
63 	if (!_part.empty() && _full.data() != _part.data()) {
64 		bytes::move(_full, _part);
65 		_part = _full.subspan(0, _part.size());
66 	}
67 	const auto amount = std::min(
68 		left,
69 		int64(_full.size() - _part.size()));
70 	Assert(amount > 0);
71 	const auto readBytes = _binlog.read(
72 		_full.subspan(_part.size(), amount));
73 	if (!readBytes) {
74 		return no();
75 	}
76 	_part = _full.subspan(0, _part.size() + readBytes);
77 	return true;
78 }
79 
readRecord(ReadRecordSize readRecordSize)80 bytes::const_span BinlogWrapper::readRecord(ReadRecordSize readRecordSize) {
81 	if (_finished) {
82 		return {};
83 	}
84 	const auto size = readRecordSize(*this, _part);
85 	if (size == kRecordSizeUnknown || size > _part.size()) {
86 		return {};
87 	} else if (size == kRecordSizeInvalid) {
88 		finish();
89 		_finished = _failed = true;
90 		return {};
91 	}
92 	Assert(size >= 0);
93 	const auto result = _part.subspan(0, size);
94 	_part = _part.subspan(size);
95 	return result;
96 }
97 
finish(size_type rollback)98 void BinlogWrapper::finish(size_type rollback) {
99 	Expects(rollback >= 0);
100 
101 	if (rollback > 0) {
102 		_failed = true;
103 	}
104 	rollback += _part.size();
105 	_binlog.seek(_binlog.offset() - rollback);
106 }
107 
108 } // namespace details
109 } // namespace Cache
110 } // namespace Storage
111