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