forked from google/centipede
-
Notifications
You must be signed in to change notification settings - Fork 5
/
blob_file.cc
140 lines (122 loc) · 4.9 KB
/
blob_file.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2022 The Centipede Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "./blob_file.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string_view>
#include <vector>
#include "absl/status/status.h"
#include "absl/types/span.h"
#include "./defs.h"
#include "./logging.h"
#include "./remote_file.h"
#include "./util.h"
namespace centipede {
// Simple implementation of BlobFileReader/BlobFileAppender based on
// PackBytesForAppendFile() / UnpackBytesFromAppendFile().
// We expect to eventually replace this code with something more robust,
// and efficient, e.g. possibly https://github.com/google/riegeli.
// But the current implementation is fully functional.
class SimpleBlobFileReader : public BlobFileReader {
public:
~SimpleBlobFileReader() override {
if (file_ && !closed_) {
// Virtual resolution is off in dtors, so use a specific Close().
CHECK_OK(SimpleBlobFileReader::Close());
}
}
absl::Status Open(std::string_view path) override {
if (closed_) return absl::FailedPreconditionError("already closed");
if (file_) return absl::FailedPreconditionError("already open");
file_ = RemoteFileOpen(path, "r");
if (file_ == nullptr) return absl::UnknownError("can't open file");
// Read the entire file at once.
// It may be useful to read the file in chunks, but if we are going
// to migrate to something else, it's not important here.
ByteArray raw_bytes;
RemoteFileRead(file_, raw_bytes);
RemoteFileClose(file_); // close the file here, we won't need it.
UnpackBytesFromAppendFile(raw_bytes, &unpacked_blobs_);
return absl::OkStatus();
}
absl::Status Read(absl::Span<uint8_t> &blob) override {
if (closed_) return absl::FailedPreconditionError("already closed");
if (!file_) return absl::FailedPreconditionError("was not open");
if (next_to_read_blob_index_ == unpacked_blobs_.size())
return absl::OutOfRangeError("no more blobs");
if (next_to_read_blob_index_ != 0) // Clear the previous blob to save RAM.
unpacked_blobs_[next_to_read_blob_index_ - 1].clear();
blob = absl::Span<uint8_t>(unpacked_blobs_[next_to_read_blob_index_]);
++next_to_read_blob_index_;
return absl::OkStatus();
}
// Closes the file (it must be open).
absl::Status Close() override {
if (closed_) return absl::FailedPreconditionError("already closed");
if (!file_) return absl::FailedPreconditionError("was not open");
closed_ = true;
// Nothing to do here, we've already closed the file (in Open()).
return absl::OkStatus();
}
private:
RemoteFile *file_ = nullptr;
bool closed_ = false;
std::vector<ByteArray> unpacked_blobs_;
size_t next_to_read_blob_index_ = 0;
};
// See SimpleBlobFileReader.
class SimpleBlobFileAppender : public BlobFileAppender {
public:
~SimpleBlobFileAppender() override {
if (file_ && !closed_) {
// Virtual resolution is off in dtors, so use a specific Close().
CHECK_OK(SimpleBlobFileAppender::Close());
}
}
absl::Status Open(std::string_view path) override {
if (closed_) return absl::FailedPreconditionError("already closed");
if (file_) return absl::FailedPreconditionError("already open");
file_ = RemoteFileOpen(path, "a");
if (file_ == nullptr) return absl::UnknownError("can't open file");
return absl::OkStatus();
}
absl::Status Append(absl::Span<const uint8_t> blob) override {
if (closed_) return absl::FailedPreconditionError("already closed");
if (!file_) return absl::FailedPreconditionError("was not open");
// TODO(kcc): [as-needed] This copy from a span to vector is clumsy. Change
// RemoteFileAppend to accept a span.
ByteArray bytes(blob.begin(), blob.end());
ByteArray packed = PackBytesForAppendFile(bytes);
RemoteFileAppend(file_, packed);
return absl::OkStatus();
}
absl::Status Close() override {
if (closed_) return absl::FailedPreconditionError("already closed");
if (!file_) return absl::FailedPreconditionError("was not open");
closed_ = true;
RemoteFileClose(file_);
return absl::OkStatus();
}
private:
RemoteFile *file_ = nullptr;
bool closed_ = false;
};
std::unique_ptr<BlobFileReader> DefaultBlobFileReaderFactory() {
return std::make_unique<SimpleBlobFileReader>();
}
std::unique_ptr<BlobFileAppender> DefaultBlobFileAppenderFactory() {
return std::make_unique<SimpleBlobFileAppender>();
}
} // namespace centipede