xref: /aosp_15_r20/external/pigweed/pw_blob_store/public/pw_blob_store/blob_store.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstddef>
17 
18 #include "pw_assert/assert.h"
19 #include "pw_blob_store/internal/metadata_format.h"
20 #include "pw_bytes/span.h"
21 #include "pw_kvs/checksum.h"
22 #include "pw_kvs/flash_memory.h"
23 #include "pw_kvs/key_value_store.h"
24 #include "pw_span/span.h"
25 #include "pw_status/status.h"
26 #include "pw_status/status_with_size.h"
27 #include "pw_status/try.h"
28 #include "pw_stream/seek.h"
29 #include "pw_stream/stream.h"
30 #include "pw_sync/borrow.h"
31 
32 namespace pw::blob_store {
33 
34 // BlobStore is a storage container for a single blob of data. BlobStore is
35 // a FlashPartition-backed persistent storage system with integrated data
36 // integrity checking that serves as a lightweight alternative to a file
37 // system.
38 //
39 // Write and read are only done using the BlobWriter and BlobReader classes.
40 //
41 // Once a blob write is closed, reopening to write will discard the previous
42 // blob.
43 //
44 // Write blob:
45 //  0) Create BlobWriter instance
46 //  1) BlobWriter::Open().
47 //  2) Add data using BlobWriter::Write().
48 //  3) BlobWriter::Close().
49 //
50 // Read blob:
51 //  0) Create BlobReader instance
52 //  1) BlobReader::Open().
53 //  2) Read data using BlobReader::Read() or
54 //     BlobReader::GetMemoryMappedBlob().
55 //  3) BlobReader::Close().
56 class BlobStore {
57  public:
58   // Implement the stream::Writer and erase interface for a BlobStore. If not
59   // already erased, the Write will do any needed erase.
60   //
61   // Only one writter (of either type) is allowed to be open at a time.
62   // Additionally, writers are unable to open if a reader is already open.
63   class BlobWriter : public stream::NonSeekableWriter {
64    public:
BlobWriter(BlobStore & store,ByteSpan metadata_buffer)65     constexpr BlobWriter(BlobStore& store, ByteSpan metadata_buffer)
66         : store_(store), metadata_buffer_(metadata_buffer), open_(false) {}
67     BlobWriter(const BlobWriter&) = delete;
68     BlobWriter& operator=(const BlobWriter&) = delete;
~BlobWriter()69     ~BlobWriter() override {
70       if (open_) {
71         Close().IgnoreError();  // TODO: b/242598609 - Handle Status properly
72       }
73     }
74 
RequiredMetadataBufferSize(size_t max_file_name_size)75     static constexpr size_t RequiredMetadataBufferSize(
76         size_t max_file_name_size) {
77       return max_file_name_size + sizeof(internal::BlobMetadataHeader);
78     }
79 
80     // Open writer for writing/erasing of a new/fresh blob. Open will invalidate
81     // any existing blob that may be stored, and will not retain the previous
82     // file name. Can not open when any readers or writers are already open for
83     // this blob. Only one writer is allowed to be open at a time. Returns:
84     //
85     // Preconditions:
86     // This writer must not already be open.
87     // This writer's metadata encode buffer must be at least the size of
88     // internal::BlobMetadataHeader.
89     //
90     // OK - success.
91     // UNAVAILABLE - Unable to open, another writer or reader instance is
92     //     already open.
93     Status Open();
94 
95     // Open and resume an in-progress/interrupted blob for writing. This will
96     // check for any existing write-in-prgress blob (not Closed) that may be
97     // partially stored, interrupted by a crash, reboot, or other reason.
98     // Resume writing at the last known good write location.
99     //
100     // If no in-progress/interrupted blob write is found, a normal Open() for
101     // writing is performed.
102     //
103     // File name in writer instance is retained from the previous Abandon()
104     // write, but not persisted across new writer instances.
105     //
106     // Checksum of resumed write is calculated from data written to flash.
107     //
108     // Can not resume when already open. Only one writer is allowed to be open
109     // at a time.
110     //
111     // Current implementation can only resume blob writes that was Abandon() or
112     // interrupted by crash/reboot. Completed valid blobs are not able to be
113     // resumed to append additional data (support not implemented at this time).
114     //
115     // Preconditions:
116     // - This writer must not already be open.
117     // - Blob must not be valid. Opening a completed blob to append is not
118     //   currently supported.
119     // - This writer's metadata encode buffer must be at
120     //   least the size of internal::BlobMetadataHeader.
121     //
122     // Returns:
123     //   OK, size - Number of bytes already written in the resumed blob write.
124     //   UNAVAILABLE - Unable to resume, another writer or reader instance is
125     //     already open.
126     StatusWithSize Resume();
127 
128     // Finalize a completed blob write and change the writer state to closed.
129     // Flush all remaining buffered data to storage and store blob metadata.
130     // Close fails in the closed state, do NOT retry Close on error. An error
131     // may or may not result in an invalid blob stored (depending on the failure
132     // mode). Returns:
133     //
134     // OK - success.
135     // FAILED_PRECONDITION - can not close if not open.
136     // DATA_LOSS - Error writing data or fail to verify written data.
137     Status Close();
138 
139     // Abandon the current in-progress blob write and change the writer state to
140     // closed. Blob is left in an invalid data state (no valid data to read).
141     //
142     // After Abandon, writer can be opened either with Open to start a new blob
143     // write or Resume to resume the abandoned blob write. On resume, any bytes
144     // written to flash at the Abandon point are handled by the resume
145     // algorithm.
146     //
147     // Abandon fails in the closed state, do NOT retry Abandon on error.
148     //
149     // OK - successfully
150     // FAILED_PRECONDITION - not open.
151     Status Abandon();
152 
IsOpen()153     bool IsOpen() { return open_; }
154 
155     // Erase the blob partition and reset state for a new blob, keeping the
156     // writer in the opened state, Explicit calls to Erase are optional,
157     // beginning a write will do any needed Erase. The Erase process includes
158     // doing a Discard of any in-progress blob write but keeps the writer in the
159     // opened state. Returns:
160     //
161     // OK - success.
162     // FAILED_PRECONDITION - not open.
163     // [error status] - flash erase failed.
Erase()164     Status Erase() {
165       return open_ ? store_.Erase() : Status::FailedPrecondition();
166     }
167 
168     // Discard the current blob write and keep the writer in the opened state,
169     // ready to start a new/clean blob write. Any written bytes to this point
170     // are considered invalid and discarded.
171     //
172     // Discard does not directly perform an erase. Erase of the already written
173     // data happens either by an explicit Erase command or on-demand when first
174     // new data is written after the Discard. Returns:
175     //
176     // OK - success.
177     // FAILED_PRECONDITION - not open.
Discard()178     Status Discard() {
179       return open_ ? store_.Invalidate() : Status::FailedPrecondition();
180     }
181 
182     // Sets file name to be associated with the data written by this
183     // ``BlobWriter``. This may be changed any time before Close() is called.
184     //
185     // Calling Discard() or Erase() will clear any set file name.
186     //
187     // The underlying buffer behind file_name may be invalidated after this
188     // function returns as the string is copied to the internally managed encode
189     // buffer.
190     //
191     // Preconditions:
192     // This writer must be open.
193     //
194     // OK - successfully set file name.
195     // RESOURCE_EXHAUSTED - File name too large to fit in metadata encode
196     //   buffer, file name not set.
197     Status SetFileName(std::string_view file_name);
198 
199     // Copies the file name associated with the data written to `dest`, and
200     // returns the number of bytes written to the destination buffer. The string
201     // is not null-terminated.
202     //
203     // Returns:
204     //   OK - File name copied, size contains file name length.
205     //   RESOURCE_EXHAUSTED - `dest` too small to fit file name, size contains
206     //     first N bytes of the file name.
207     //   NOT_FOUND - No file name set for this blob.
208     //   FAILED_PRECONDITION - not open
209     //
210     StatusWithSize GetFileName(span<char> dest);
211 
CurrentSizeBytes()212     size_t CurrentSizeBytes() const {
213       return open_ ? store_.write_address_ : 0;
214     }
215 
216     // Get the current running checksum for the current write session.
217     //
218     // Returns:
219     //   ConstByteSpan - current checksum
220     //   NOT_FOUND - No checksum algo in use
221     //   FAILED_PRECONDITION - not open
222     //
CurrentChecksum()223     Result<ConstByteSpan> CurrentChecksum() const {
224       return Status::Unimplemented();
225     }
226 
227     // Max file name length, not including null terminator (null terminators
228     // are not stored).
MaxFileNameLength()229     size_t MaxFileNameLength() {
230       return metadata_buffer_.size_bytes() <
231                      sizeof(internal::BlobMetadataHeader)
232                  ? 0
233                  : metadata_buffer_.size_bytes() -
234                        sizeof(internal::BlobMetadataHeader);
235     }
236 
237    protected:
DoWrite(ConstByteSpan data)238     Status DoWrite(ConstByteSpan data) override {
239       return open_ ? store_.Write(data) : Status::FailedPrecondition();
240     }
241 
242     // Commits changes to KVS as a BlobStore metadata entry.
243     Status WriteMetadata();
244 
245     BlobStore& store_;
246     ByteSpan metadata_buffer_;
247     bool open_;
248 
249    private:
250     // Probable (not guaranteed) minimum number of bytes at this time that can
251     // be written. This is not necessarily the full number of bytes remaining in
252     // the blob. Returns zero if, in the current state, Write would return
253     // status other than OK. See stream.h for additional details.
ConservativeLimit(LimitType limit)254     size_t ConservativeLimit(LimitType limit) const override {
255       if (open_ && limit == LimitType::kWrite) {
256         return store_.WriteBytesRemaining();
257       }
258       return 0;
259     }
260   };
261 
262   template <size_t kMaxFileNameSize = 0>
263   class BlobWriterWithBuffer final : public BlobWriter {
264    public:
BlobWriterWithBuffer(BlobStore & store)265     constexpr BlobWriterWithBuffer(BlobStore& store)
266         : BlobWriter(store, buffer_), buffer_() {}
267 
268    private:
269     std::array<std::byte, RequiredMetadataBufferSize(kMaxFileNameSize)> buffer_;
270   };
271 
272   // Implement the stream::Writer and erase interface with deferred action for a
273   // BlobStore. If not already erased, the Flush will do any needed erase.
274   //
275   // Only one writter (of either type) is allowed to be open at a time.
276   // Additionally, writers are unable to open if a reader is already open.
277   class DeferredWriter : public BlobWriter {
278    public:
DeferredWriter(BlobStore & store,ByteSpan metadata_buffer)279     constexpr DeferredWriter(BlobStore& store, ByteSpan metadata_buffer)
280         : BlobWriter(store, metadata_buffer) {}
281     DeferredWriter(const DeferredWriter&) = delete;
282     DeferredWriter& operator=(const DeferredWriter&) = delete;
~DeferredWriter()283     ~DeferredWriter() override {}
284 
285     // Flush data in the write buffer. Only a multiple of flash_write_size_bytes
286     // are written in the flush. Any remainder is held until later for either
287     // a flush with flash_write_size_bytes buffered or the writer is closed.
Flush()288     Status Flush() {
289       return open_ ? store_.Flush() : Status::FailedPrecondition();
290     }
291 
292     // Probable (not guaranteed) minimum number of bytes at this time that can
293     // be written. This is not necessarily the full number of bytes remaining in
294     // the blob. Returns zero if, in the current state, Write would return
295     // status other than OK. See stream.h for additional details.
ConservativeLimit(LimitType limit)296     size_t ConservativeLimit(LimitType limit) const final {
297       if (open_ && limit == LimitType::kWrite) {
298         // Deferred writes need to fit in the write buffer.
299         return store_.WriteBufferBytesFree();
300       }
301       return 0;
302     }
303 
304    private:
305     // Similar to normal Write, but instead immediately writing out to flash,
306     // it only buffers the data. A flush or Close is reqired to get bytes
307     // writen out to flash.
308     //
309     // AddToWriteBuffer will continue to accept new data after Flush has an
310     // erase error (buffer space permitting). Write errors during Flush will
311     // result in no new data being accepted.
DoWrite(ConstByteSpan data)312     Status DoWrite(ConstByteSpan data) final {
313       return open_ ? store_.AddToWriteBuffer(data)
314                    : Status::FailedPrecondition();
315     }
316   };
317 
318   template <size_t kMaxFileNameSize = 0>
319   class DeferredWriterWithBuffer final : public DeferredWriter {
320    public:
DeferredWriterWithBuffer(BlobStore & store)321     constexpr DeferredWriterWithBuffer(BlobStore& store)
322         : DeferredWriter(store, buffer_), buffer_() {}
323 
324    private:
325     std::array<std::byte, RequiredMetadataBufferSize(kMaxFileNameSize)> buffer_;
326   };
327 
328   // Implement stream::Reader interface for BlobStore. Multiple readers may be
329   // open at the same time, but readers may not be open with a writer open.
330   class BlobReader final : public stream::SeekableReader {
331    public:
BlobReader(BlobStore & store)332     constexpr BlobReader(BlobStore& store)
333         : store_(store), open_(false), offset_(0) {}
334 
335     BlobReader(const BlobReader&) = delete;
336     BlobReader& operator=(const BlobReader&) = delete;
337 
~BlobReader()338     ~BlobReader() override {
339       if (open_) {
340         Close().IgnoreError();
341       }
342     }
343 
344     // Open to do a blob read at the given offset in to the blob. Can not open
345     // when already open. Multiple readers can be open at the same time.
346     // Returns:
347     //
348     //   OK - success.
349     //   FAILED_PRECONDITION - No readable blob available.
350     //   INVALID_ARGUMENT - Invalid offset.
351     //   UNAVAILABLE - Unable to open, already open.
352     //
353     Status Open(size_t offset = 0);
354 
355     // Finish reading a blob. Close fails in the closed state, do NOT retry
356     // Close on error. Returns:
357     //
358     //   OK - success
359     //   FAILED_PRECONDITION - already closed
360     //
Close()361     Status Close() {
362       if (!open_) {
363         return Status::FailedPrecondition();
364       }
365       open_ = false;
366       return store_.CloseRead();
367     }
368 
369     // Copies the file name of the stored data to `dest`, and returns the number
370     // of bytes written to the destination buffer. The string is not
371     // null-terminated.
372     //
373     // Returns:
374     //   OK - File name copied, size contains file name length.
375     //   RESOURCE_EXHAUSTED - `dest` too small to fit file name, size contains
376     //     first N bytes of the file name.
377     //   NOT_FOUND - No file name set for this blob.
378     //   FAILED_PRECONDITION - not open
379     //
GetFileName(span<char> dest)380     StatusWithSize GetFileName(span<char> dest) {
381       return open_ ? store_.GetFileName(dest)
382                    : StatusWithSize::FailedPrecondition();
383     }
384 
IsOpen()385     bool IsOpen() const { return open_; }
386 
387     // Get a span with the MCU pointer and size of the data. Returns:
388     //
389     //   OK with span - Valid span respresenting the blob data
390     //   FAILED_PRECONDITION - Reader not open.
391     //   UNIMPLEMENTED - Memory mapped access not supported for this blob.
392     //   FAILED_PRECONDITION - Writer is closed
393     //
GetMemoryMappedBlob()394     Result<ConstByteSpan> GetMemoryMappedBlob() {
395       return open_ ? store_.GetMemoryMappedBlob()
396                    : Status::FailedPrecondition();
397     }
398 
399    private:
400     // Probable (not guaranteed) minimum number of bytes at this time that can
401     // be read. Returns zero if, in the current state, Read would return status
402     // other than OK. See stream.h for additional details.
403     size_t ConservativeLimit(LimitType limit) const override;
404 
405     size_t DoTell() override;
406 
407     Status DoSeek(ptrdiff_t offset, Whence origin) override;
408 
409     StatusWithSize DoRead(ByteSpan dest) override;
410 
411     BlobStore& store_;
412     bool open_;
413     size_t offset_;
414   };
415 
416   // BlobStore
417   // name - Name of blob store, used for metadata KVS key
418   // partition - Flash partiton to use for this blob. Blob uses the entire
419   //     partition for blob data.
420   // checksum_algo - Optional checksum for blob integrity checking. Use nullptr
421   //     for no check.
422   // kvs - KVS used for storing blob metadata.
423   // write_buffer - Used for buffering writes. Needs to be at least
424   //     flash_write_size_bytes.
425   // flash_write_size_bytes - Size in bytes to use for flash write operations.
426   //     This should be chosen to balance optimal write size and required buffer
427   //     size. Must be greater than or equal to flash write alignment, less than
428   //     or equal to flash sector size.
BlobStore(std::string_view name,kvs::FlashPartition & partition,kvs::ChecksumAlgorithm * checksum_algo,sync::Borrowable<kvs::KeyValueStore> kvs,ByteSpan write_buffer,size_t flash_write_size_bytes)429   BlobStore(std::string_view name,
430             kvs::FlashPartition& partition,
431             kvs::ChecksumAlgorithm* checksum_algo,
432             sync::Borrowable<kvs::KeyValueStore> kvs,
433             ByteSpan write_buffer,
434             size_t flash_write_size_bytes)
435       : name_(name),
436         partition_(partition),
437         checksum_algo_(checksum_algo),
438         kvs_(kvs),
439         write_buffer_(write_buffer),
440         flash_write_size_bytes_(flash_write_size_bytes),
441         initialized_(false),
442         valid_data_(false),
443         flash_erased_(false),
444         writer_open_(false),
445         readers_open_(0),
446         write_address_(0),
447         flash_address_(0),
448         file_name_length_(0) {}
449 
450   BlobStore(const BlobStore&) = delete;
451   BlobStore& operator=(const BlobStore&) = delete;
452 
453   // Initialize the blob instance. Checks if storage is erased or has any stored
454   // blob data. Returns:
455   //
456   // OK - success.
457   Status Init();
458 
459   // Maximum number of data bytes this BlobStore is able to store.
460   size_t MaxDataSizeBytes() const;
461 
462   // Get the current data state of the blob without needing to instantiate
463   // and/or open a reader or writer. This check is independent of any writers or
464   // readers of this blob that might exist (open or closed).
465   //
466   // NOTE: This state can be changed by any writer that is open(ed) for this
467   //       blob. Readers can not be opened until any open writers are closed.
468   //
469   // true -  Blob is valid/OK and has at least 1 data byte.
470   // false -  Blob is either invalid or does not have any data bytes
HasData()471   bool HasData() const { return (valid_data_ && ReadableDataBytes() > 0); }
472 
473  private:
474   Status LoadMetadata();
475 
476   // Open to do a blob write. Returns:
477   //
478   // OK - success.
479   // UNAVAILABLE - Unable to open writer, another writer or reader instance is
480   //     already open.
481   Status OpenWrite();
482 
483   // Open to resume a blob write. Returns:
484   //
485   // size - Number of bytes already written in the resumed blob write.
486   // UNAVAILABLE - Unable to open writer, another writer or reader instance is
487   //     already open.
488   StatusWithSize ResumeWrite();
489 
490   // Open to do a blob read. Returns:
491   //
492   // OK - success.
493   // FAILED_PRECONDITION - Unable to open, no valid blob available.
494   Status OpenRead();
495 
496   // Finalize a blob write. Flush all remaining buffered data to storage and
497   // store blob metadata. Returns:
498   //
499   // OK - success, valid complete blob.
500   // DATA_LOSS - Error during write (this close or previous write/flush). Blob
501   //     is closed and marked as invalid.
502   Status CloseRead();
503 
504   // Write/append data to the in-progress blob write. Data is written
505   // sequentially, with each append added directly after the previous. Data is
506   // not guaranteed to be fully written out to storage on Write return. Returns:
507   //
508   // OK - successful write/enqueue of data.
509   // RESOURCE_EXHAUSTED - unable to write all of requested data at this time. No
510   //     data written.
511   // OUT_OF_RANGE - Writer has been exhausted, similar to EOF. No data written,
512   //     no more will be written.
513   // DATA_LOSS - Error during write (this write or previous write/flush). No
514   //     more will be written by following Write calls for current blob (until
515   //     erase/new blob started).
516   Status Write(ConstByteSpan data);
517 
518   // Similar to Write, but instead immediately writing out to flash, it only
519   // buffers the data. A flush or Close is reqired to get bytes writen out to
520   // flash.
521   //
522   // AddToWriteBuffer will continue to accept new data after Flush has an erase
523   // error (buffer space permitting). Write errors during Flush will result in
524   // no new data being accepted.
525   //
526   // OK - successful write/enqueue of data.
527   // RESOURCE_EXHAUSTED - unable to write all of requested data at this time. No
528   //     data written.
529   // OUT_OF_RANGE - Writer has been exhausted, similar to EOF. No data written,
530   //     no more will be written.
531   // DATA_LOSS - Error during a previous write/flush. No more will be written by
532   //     following Write calls for current blob (until erase/new blob started).
533   Status AddToWriteBuffer(ConstByteSpan data);
534 
535   // Flush data in the write buffer. Only a multiple of flash_write_size_bytes
536   // are written in the flush. Any remainder is held until later for either a
537   // flush with flash_write_size_bytes buffered or the writer is closed.
538   //
539   // OK - successful write/enqueue of data.
540   // DATA_LOSS - Error during write (this flush or previous write/flush). No
541   //     more will be written by following Write calls for current blob (until
542   //     erase/new blob started).
543   Status Flush();
544 
545   // Flush a chunk of data in the write buffer smaller than
546   // flash_write_size_bytes. This is only for the final flush as part of the
547   // CloseWrite. The partial chunk is padded to flash_write_size_bytes and a
548   // flash_write_size_bytes chunk is written to flash.
549   //
550   // OK - successful write/enqueue of data.
551   // DATA_LOSS - Error during write (this flush or previous write/flush). No
552   //     more will be written by following Write calls for current blob (until
553   //     erase/new blob started).
554   Status FlushFinalPartialChunk();
555 
556   // Commit data to flash and update flash_address_ with data bytes written. The
557   // only time data_bytes should be manually specified is for a CloseWrite with
558   // an unaligned-size chunk remaining in the buffer that has been zero padded
559   // to alignment.
560   Status CommitToFlash(ConstByteSpan source, size_t data_bytes = 0);
561 
562   // Blob is valid/OK to write to. Blob is considered valid to write if no data
563   // has been written due to the auto/implicit erase on write start.
564   //
565   // true - Blob is valid and OK to write to.
566   // false - Blob has previously had an error and not valid for writing new
567   //     data.
ValidToWrite()568   bool ValidToWrite() { return (valid_data_ == true) || (flash_address_ == 0); }
569 
WriteBufferEmpty()570   bool WriteBufferEmpty() const { return flash_address_ == write_address_; }
571 
572   size_t WriteBufferBytesUsed() const;
573 
574   size_t WriteBufferBytesFree() const;
575 
576   Status EraseIfNeeded();
577 
578   // Read valid data. Attempts to read the lesser of output.size_bytes() or
579   // available bytes worth of data. Returns:
580   //
581   // OK with span of bytes read - success, between 1 and dest.size_bytes() were
582   //     read.
583   // INVALID_ARGUMENT - offset is invalid.
584   // FAILED_PRECONDITION - Reader unable/not in state to read data.
585   // RESOURCE_EXHAUSTED - unable to read any bytes at this time. No bytes read.
586   //     Try again once bytes become available.
587   // OUT_OF_RANGE - Reader has been exhausted, similar to EOF. No bytes read, no
588   //     more will be read.
589   StatusWithSize Read(size_t offset, ByteSpan dest) const;
590 
591   // Get a span with the MCU pointer and size of the data. Returns:
592   //
593   // OK with span - Valid span respresenting the blob data
594   // FAILED_PRECONDITION - Blob not in a state to read data
595   // UNIMPLEMENTED - Memory mapped access not supported for this blob.
596   Result<ConstByteSpan> GetMemoryMappedBlob() const;
597 
598   // Size of blob/readable data, in bytes.
599   size_t ReadableDataBytes() const;
600 
WriteBytesRemaining()601   size_t WriteBytesRemaining() const {
602     return MaxDataSizeBytes() - write_address_;
603   }
604 
605   Status Erase();
606 
607   Status Invalidate();
608 
ResetChecksum()609   void ResetChecksum() {
610     if (checksum_algo_ != nullptr) {
611       checksum_algo_->Reset();
612     }
613   }
614 
615   Status ValidateChecksum(size_t blob_size_bytes,
616                           internal::ChecksumValue expected);
617 
618   Status CalculateChecksumFromFlash(size_t bytes_to_check, bool finish = true);
619 
MetadataKey()620   const std::string_view MetadataKey() const { return name_; }
621 
622   // Copies the file name of the stored data to `dest`, and returns the number
623   // of bytes written to the destination buffer. The string is not
624   // null-terminated.
625   //
626   // Returns:
627   //   OK - File name copied, size contains file name length.
628   //   RESOURCE_EXHAUSTED - `dest` too small to fit file name, size contains
629   //     first N bytes of the file name.
630   //   NOT_FOUND - No file name set for this blob.
631   //   FAILED_PRECONDITION - BlobStore has not been initialized.
632   StatusWithSize GetFileName(span<char> dest) const;
633 
634   std::string_view name_;
635   kvs::FlashPartition& partition_;
636   // checksum_algo_ of nullptr indicates no checksum algorithm.
637   kvs::ChecksumAlgorithm* const checksum_algo_;
638   sync::Borrowable<kvs::KeyValueStore> kvs_;
639   ByteSpan write_buffer_;
640 
641   // Size in bytes of flash write operations. This should be chosen to balance
642   // optimal write size and required buffer size. Must be GE flash write
643   // alignment, LE flash sector size.
644   const size_t flash_write_size_bytes_;
645 
646   //
647   // Internal state for Blob store
648   //
649   // TODO(davidrogers): Consolidate blob state to a single struct
650 
651   // Initialization has been done.
652   bool initialized_;
653 
654   // Bytes stored are valid and good. Blob is OK to read and write to. Set as
655   // soon as blob is erased. Even when bytes written is still 0, they are valid.
656   bool valid_data_;
657 
658   // Blob partition is currently erased and ready to write a new blob.
659   bool flash_erased_;
660 
661   // BlobWriter instance is currently open
662   bool writer_open_;
663 
664   // Count of open BlobReader instances
665   size_t readers_open_;
666 
667   // Current index for end of overall blob data. Represents current byte size of
668   // blob data since the FlashPartition starts at address 0.
669   kvs::FlashPartition::Address write_address_;
670 
671   // Current index of end of data written to flash. Number of buffered data
672   // bytes is write_address_ - flash_address_.
673   kvs::FlashPartition::Address flash_address_;
674 
675   // Length of the stored blob's filename.
676   size_t file_name_length_;
677 };
678 
679 // Creates a BlobStore with the buffer of kBufferSizeBytes.
680 //
681 // kBufferSizeBytes - Size in bytes of write buffer to create.
682 // name - Name of blob store, used for metadata KVS key
683 // partition - Flash partition to use for this blob. Blob uses the entire
684 //     partition for blob data.
685 // checksum_algo - Optional checksum for blob integrity checking. Use nullptr
686 //     for no check.
687 // kvs - KVS used for storing blob metadata.
688 // write_buffer - Used for buffering writes. Needs to be at least
689 //     flash_write_size_bytes.
690 // flash_write_size_bytes - Size in bytes to use for flash write operations.
691 //     This should be chosen to balance optimal write size and required buffer
692 //     size. Must be greater than or equal to flash write alignment, less than
693 //     or equal to flash sector size.
694 
695 template <size_t kBufferSizeBytes>
696 class BlobStoreBuffer : public BlobStore {
697  public:
BlobStoreBuffer(std::string_view name,kvs::FlashPartition & partition,kvs::ChecksumAlgorithm * checksum_algo,sync::Borrowable<kvs::KeyValueStore> kvs,size_t flash_write_size_bytes)698   explicit BlobStoreBuffer(std::string_view name,
699                            kvs::FlashPartition& partition,
700                            kvs::ChecksumAlgorithm* checksum_algo,
701                            sync::Borrowable<kvs::KeyValueStore> kvs,
702                            size_t flash_write_size_bytes)
703       : BlobStore(name,
704                   partition,
705                   checksum_algo,
706                   kvs,
707                   buffer_,
708                   flash_write_size_bytes) {}
709 
710  private:
711   std::array<std::byte, kBufferSizeBytes> buffer_;
712 };
713 
714 }  // namespace pw::blob_store
715