Implement commit
The commit operation will serialize the binarystore protobuf and write
it to the designated sysfile location, with its size stored followed by
actual data.
Signed-off-by: Kun Yi <kunyi@google.com>
Change-Id: Idc16f410d3a1585daaddda58a3665d92a898f5c7
diff --git a/binarystore.cpp b/binarystore.cpp
index 98a6264..22e2e48 100644
--- a/binarystore.cpp
+++ b/binarystore.cpp
@@ -20,6 +20,42 @@
namespace binstore
{
+namespace internal
+{
+
+/* Helper methods to interconvert an uint64_t and bytes, LSB first.
+ Convert bytes to uint64. Input should be exactly 8 bytes. */
+uint64_t bytesToUint64(const std::string& bytes)
+{
+ if (bytes.size() != sizeof(uint64_t))
+ {
+ return 0;
+ }
+
+ return static_cast<uint64_t>(bytes[7]) << 56 |
+ static_cast<uint64_t>(bytes[6]) << 48 |
+ static_cast<uint64_t>(bytes[5]) << 40 |
+ static_cast<uint64_t>(bytes[4]) << 32 |
+ static_cast<uint64_t>(bytes[3]) << 24 |
+ static_cast<uint64_t>(bytes[2]) << 16 |
+ static_cast<uint64_t>(bytes[1]) << 8 |
+ static_cast<uint64_t>(bytes[0]);
+}
+
+/* Convert uint64 to bytes, LSB first. */
+std::string uint64ToBytes(uint64_t num)
+{
+ std::string result;
+ for (size_t i = 0; i < sizeof(uint64_t); ++i)
+ {
+ result += static_cast<char>(num & 0xff);
+ num >>= 8;
+ }
+ return result;
+}
+
+} // namespace internal
+
std::unique_ptr<BinaryStoreInterface>
BinaryStore::createFromConfig(const std::string& baseBlobId,
std::unique_ptr<SysFile> file,
@@ -71,6 +107,31 @@
writable_ = flags & blobs::OpenFlags::write;
+ /* Load blob from sysfile if we know it might not match what we have.
+ * Note it will overwrite existing unsaved data per design. */
+ if (commitState_ != CommitState::Clean)
+ {
+ try
+ {
+ /* Parse length-prefixed format to protobuf */
+ auto size =
+ internal::bytesToUint64(file_->readAsStr(0, sizeof(uint64_t)));
+ if (!blob_.ParseFromString(
+ file_->readAsStr(sizeof(uint64_t), size)))
+ {
+ /* Fail to parse the data, which might mean no preexsiting data
+ * and is a valid case to handle */
+ // TODO: logging
+ }
+ }
+ catch (const std::exception& e)
+ {
+ /* Read causes unexpected system-level failure */
+ // TODO: logging
+ return false;
+ }
+ }
+
/* Iterate and find if there is an existing blob with this id.
* blobsPtr points to a BinaryBlob container with STL-like semantics*/
auto blobsPtr = blob_.mutable_blobs();
@@ -152,13 +213,31 @@
bool BinaryStore::commit()
{
- return false;
+
+ auto blobData = blob_.SerializeAsString();
+ std::string commitData(internal::uint64ToBytes((uint64_t)blobData.size()));
+ commitData += blobData;
+
+ try
+ {
+ file_->writeStr(commitData, 0);
+ }
+ catch (const std::exception& e)
+ {
+ // TODO: logging
+ commitState_ = CommitState::CommitError;
+ return false;
+ };
+
+ commitState_ = CommitState::Clean;
+ return true;
}
bool BinaryStore::close()
{
currentBlob_ = nullptr;
writable_ = false;
+ commitState_ = CommitState::Dirty;
return true;
}