pw_kvs: Add to build; get tests passing
Change-Id: Idfd357beaf60b94ebaf9b4b1f8cd1b3d712e9b10
diff --git a/BUILD.gn b/BUILD.gn
index 0a0b5f2..6379134 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -53,6 +53,7 @@
"$dir_pigweed/docs",
"$dir_pw_base64",
"$dir_pw_checksum",
+ "$dir_pw_kvs",
"$dir_pw_polyfill",
"$dir_pw_preprocessor",
"$dir_pw_protobuf",
@@ -70,6 +71,7 @@
group_deps = [
"$dir_pw_base64:tests",
"$dir_pw_checksum:tests",
+ "$dir_pw_kvs:tests",
"$dir_pw_log:tests",
"$dir_pw_polyfill:tests",
"$dir_pw_preprocessor:tests",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7b5d46..d8ed777 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@
add_subdirectory(pw_cpu_exception_armv7m)
add_subdirectory(pw_dumb_io)
add_subdirectory(pw_dumb_io_stdio)
+add_subdirectory(pw_kvs)
add_subdirectory(pw_log)
add_subdirectory(pw_log_basic)
add_subdirectory(pw_polyfill)
diff --git a/modules.gni b/modules.gni
index d122bae..41fe5cf 100644
--- a/modules.gni
+++ b/modules.gni
@@ -29,6 +29,7 @@
dir_pw_dumb_io_baremetal_stm32f429 =
"$dir_pigweed/pw_dumb_io_baremetal_stm32f429"
dir_pw_dumb_io_stdio = "$dir_pigweed/pw_dumb_io_stdio"
+dir_pw_kvs = "$dir_pigweed/pw_kvs"
dir_pw_log = "$dir_pigweed/pw_log"
dir_pw_log_basic = "$dir_pigweed/pw_log_basic"
dir_pw_module = "$dir_pigweed/pw_module"
diff --git a/pw_kvs/BUILD b/pw_kvs/BUILD
new file mode 100644
index 0000000..b646357
--- /dev/null
+++ b/pw_kvs/BUILD
@@ -0,0 +1,66 @@
+# Copyright 2020 The Pigweed 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.
+
+load(
+ "//pw_build:pigweed.bzl",
+ "pw_cc_library",
+ "pw_cc_test",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache License 2.0
+
+pw_cc_library(
+ name = "pw_kvs",
+ srcs = [
+ "flash.cc",
+ "key_value_store.cc",
+ ],
+ hdrs = [
+ "public/pw_kvs/assert.h",
+ "public/pw_kvs/flash.h",
+ "public/pw_kvs/flash_memory.h",
+ "public/pw_kvs/in_memory_fake_flash.h",
+ "public/pw_kvs/key_value_store.h",
+ "public/pw_kvs/partition_table_entry.h",
+ ],
+ includes = ["public"],
+ deps = [
+ "//pw_checksum",
+ "//pw_log",
+ "//pw_status",
+ "//pw_string",
+ ],
+)
+
+pw_cc_test(
+ name = "key_value_store_test",
+ srcs = ["key_value_store_test.cc"],
+ deps = [
+ ":pw_kvs",
+ "//pw_checksum",
+ "//pw_log",
+ ],
+)
+
+pw_cc_test(
+ name = "key_value_store_sub_sector_test",
+ srcs = ["key_value_store_sub_sector_test.cc"],
+ deps = [
+ ":pw_kvs",
+ "//pw_checksum",
+ "//pw_log",
+ ],
+)
diff --git a/pw_kvs/BUILD.gn b/pw_kvs/BUILD.gn
new file mode 100644
index 0000000..0c59dd1
--- /dev/null
+++ b/pw_kvs/BUILD.gn
@@ -0,0 +1,80 @@
+# Copyright 2020 The Pigweed 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.
+
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+config("default_config") {
+ include_dirs = [ "public" ]
+}
+
+source_set("pw_kvs") {
+ public_configs = [ ":default_config" ]
+ public = [
+ "public/pw_kvs/assert.h",
+ "public/pw_kvs/flash.h",
+ "public/pw_kvs/flash_memory.h",
+ "public/pw_kvs/in_memory_fake_flash.h",
+ "public/pw_kvs/key_value_store.h",
+ "public/pw_kvs/partition_table_entry.h",
+ ]
+ sources = [
+ "flash.cc",
+ "key_value_store.cc",
+ ]
+ sources += public
+ public_deps = [
+ "$dir_pw_status",
+ ]
+ deps = [
+ dir_pw_checksum,
+ dir_pw_log,
+ dir_pw_string,
+ ]
+}
+
+pw_test_group("tests") {
+ tests = [
+ ":key_value_store_test",
+ ":key_value_store_sub_sector_test",
+ ]
+}
+
+pw_test("key_value_store_test") {
+ deps = [
+ ":pw_kvs",
+ dir_pw_checksum,
+ dir_pw_log,
+ ]
+ sources = [
+ "key_value_store_test.cc",
+ ]
+}
+
+pw_test("key_value_store_sub_sector_test") {
+ deps = [
+ ":pw_kvs",
+ dir_pw_checksum,
+ dir_pw_log,
+ ]
+ sources = [
+ "key_value_store_sub_sector_test.cc",
+ ]
+}
+
+pw_doc_group("docs") {
+ sources = [
+ "docs.rst",
+ ]
+}
diff --git a/pw_kvs/CMakeLists.txt b/pw_kvs/CMakeLists.txt
new file mode 100644
index 0000000..2d998bb
--- /dev/null
+++ b/pw_kvs/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright 2020 The Pigweed 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.
+
+pw_auto_add_simple_module(pw_kvs
+ PUBLIC_DEPS
+ pw_status
+ PRIVATE_DEPS
+ pw_checksum
+ pw_log
+ pw_string
+)
diff --git a/pw_kvs/flash.cc b/pw_kvs/flash.cc
index bcc695f..dad5fab 100644
--- a/pw_kvs/flash.cc
+++ b/pw_kvs/flash.cc
@@ -12,29 +12,41 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_kvs/util/flash.h"
+#include "pw_kvs/flash.h"
-#include "pw_kvs/config.h"
+#include <cstring>
-namespace pw {
+namespace pw::kvs {
+namespace cfg {
+
+// Configure the maximum supported alignment for the flash utility functions.
+constexpr size_t kFlashUtilMaxAlignmentBytes = 16;
+
+} // namespace cfg
Status PaddedWrite(FlashPartition* partition,
FlashPartition::Address address,
const uint8_t* buffer,
uint16_t size) {
- RETURN_STATUS_IF(
- address % partition->GetAlignmentBytes() ||
- partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes,
- Status::INVALID_ARGUMENT);
+ if (address % partition->GetAlignmentBytes() ||
+ partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes) {
+ return Status::INVALID_ARGUMENT;
+ }
uint8_t alignment_buffer[cfg::kFlashUtilMaxAlignmentBytes] = {0};
uint16_t aligned_bytes = size - size % partition->GetAlignmentBytes();
- RETURN_IF_ERROR(partition->Write(address, buffer, aligned_bytes));
+ if (Status status = partition->Write(address, buffer, aligned_bytes);
+ !status.ok()) {
+ return status;
+ }
uint16_t remaining_bytes = size - aligned_bytes;
if (remaining_bytes > 0) {
- memcpy(alignment_buffer, &buffer[aligned_bytes], remaining_bytes);
- RETURN_IF_ERROR(partition->Write(address + aligned_bytes,
- alignment_buffer,
- partition->GetAlignmentBytes()));
+ std::memcpy(alignment_buffer, &buffer[aligned_bytes], remaining_bytes);
+ if (Status status = partition->Write(address + aligned_bytes,
+ alignment_buffer,
+ partition->GetAlignmentBytes());
+ !status.ok()) {
+ return status;
+ }
}
return Status::OK;
}
@@ -43,21 +55,27 @@
uint8_t* buffer,
FlashPartition::Address address,
uint16_t size) {
- RETURN_STATUS_IF(
- address % partition->GetAlignmentBytes() ||
- partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes,
- Status::INVALID_ARGUMENT);
+ if (address % partition->GetAlignmentBytes() ||
+ partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes) {
+ return Status::INVALID_ARGUMENT;
+ }
uint16_t aligned_bytes = size - size % partition->GetAlignmentBytes();
- RETURN_IF_ERROR(partition->Read(buffer, address, aligned_bytes));
+ if (Status status = partition->Read(buffer, address, aligned_bytes);
+ !status.ok()) {
+ return status;
+ }
uint16_t remaining_bytes = size - aligned_bytes;
if (remaining_bytes > 0) {
uint8_t alignment_buffer[cfg::kFlashUtilMaxAlignmentBytes];
- RETURN_IF_ERROR(partition->Read(alignment_buffer,
- address + aligned_bytes,
- partition->GetAlignmentBytes()));
+ if (Status status = partition->Read(alignment_buffer,
+ address + aligned_bytes,
+ partition->GetAlignmentBytes());
+ !status.ok()) {
+ return status;
+ }
memcpy(&buffer[aligned_bytes], alignment_buffer, remaining_bytes);
}
return Status::OK;
}
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/key_value_store.cc b/pw_kvs/key_value_store.cc
index ce21740..b1a6505 100644
--- a/pw_kvs/key_value_store.cc
+++ b/pw_kvs/key_value_store.cc
@@ -46,19 +46,16 @@
#include <cstring>
-#include "pw_kvs/os/mutex.h"
-#include "pw_kvs/util/ccitt_crc16.h"
-#include "pw_kvs/util/constexpr.h"
-#include "pw_kvs/util/flash.h"
+#include "pw_checksum/ccitt_crc16.h"
+#include "pw_kvs/flash.h"
+#include "pw_log/log.h"
+#include "pw_string/string_builder.h"
+#include "pw_string/util.h"
-namespace pw {
-
-// Declare static constexpr variables so it can be used for pass-by-reference
-// functions.
-constexpr uint16_t KeyValueStore::kSectorReadyValue;
+namespace pw::kvs {
Status KeyValueStore::Enable() {
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
if (enabled_) {
return Status::OK;
}
@@ -71,9 +68,11 @@
alignment_bytes_ = partition_.GetAlignmentBytes();
DCHECK(alignment_bytes_ <= kMaxAlignmentBytes);
- LOG_WARN_IF(partition_.GetSectorCount() > kSectorCountMax,
- "Partition is larger then KVS max sector count, not all space "
- "will be used.");
+ if (partition_.GetSectorCount() > kSectorCountMax) {
+ PW_LOG_WARN(
+ "Partition is larger then KVS max sector count, "
+ "not all space will be used.");
+ }
// Load map and setup sectors if needed (first word isn't kSectorReadyValue).
next_sector_clean_order_ = 0;
for (SectorIndex i = 0; i < SectorCount(); i++) {
@@ -82,45 +81,60 @@
// may give random values. It's important to make sure that data is not
// erased before trying to see if there is a token match.
bool is_sector_meta_erased;
- RETURN_IF_ERROR(partition_.IsChunkErased(
- SectorIndexToAddress(i),
- RoundUpForAlignment(sizeof(sector_header_meta)),
- &is_sector_meta_erased));
- RETURN_IF_ERROR(
- UnalignedRead(&partition_,
- reinterpret_cast<uint8_t*>(§or_header_meta),
- SectorIndexToAddress(i),
- sizeof(sector_header_meta)));
+ if (Status status = partition_.IsChunkErased(
+ SectorIndexToAddress(i),
+ RoundUpForAlignment(sizeof(sector_header_meta)),
+ &is_sector_meta_erased);
+ !status.ok()) {
+ return status;
+ };
+ if (Status status =
+ UnalignedRead(&partition_,
+ reinterpret_cast<uint8_t*>(§or_header_meta),
+ SectorIndexToAddress(i),
+ sizeof(sector_header_meta));
+ !status.ok()) {
+ return status;
+ }
constexpr int kVersion3 = 3; // Version 3 only cleans 1 sector at a time.
constexpr int kVersion2 = 2; // Version 2 is always 1 byte aligned.
if (is_sector_meta_erased ||
sector_header_meta.synchronize_token != kSectorReadyValue) {
// Sector needs to be setup
- RETURN_IF_ERROR(ResetSector(i));
+ if (Status status = ResetSector(i); !status.ok()) {
+ return status;
+ }
continue;
} else if (sector_header_meta.version != kVersion &&
sector_header_meta.version != kVersion3 && // Allow version 3
sector_header_meta.version != kVersion2) { // Allow version 2
- LOG(ERROR) << "Unsupported KVS version in sector: " << i;
+ PW_LOG_ERROR("Unsupported KVS version in sector: %u",
+ static_cast<unsigned>(i));
return Status::FAILED_PRECONDITION;
}
uint32_t sector_header_cleaning_offset =
RoundUpForAlignment(sizeof(KvsSectorHeaderMeta));
bool clean_not_pending;
- RETURN_IF_ERROR(partition_.IsChunkErased(
- SectorIndexToAddress(i) + sector_header_cleaning_offset,
- RoundUpForAlignment(sizeof(KvsSectorHeaderCleaning)),
- &clean_not_pending));
+ if (Status status = partition_.IsChunkErased(
+ SectorIndexToAddress(i) + sector_header_cleaning_offset,
+ RoundUpForAlignment(sizeof(KvsSectorHeaderCleaning)),
+ &clean_not_pending);
+ !status.ok()) {
+ return status;
+ }
if (!clean_not_pending) {
// Sector is marked for cleaning, read the sector_clean_order
- RETURN_IF_ERROR(
- UnalignedRead(&partition_,
- reinterpret_cast<uint8_t*>(§or_clean_order_[i]),
- SectorIndexToAddress(i) + sector_header_cleaning_offset,
- sizeof(KvsSectorHeaderCleaning::sector_clean_order)));
+ if (Status status = UnalignedRead(
+ &partition_,
+ reinterpret_cast<uint8_t*>(§or_clean_order_[i]),
+ SectorIndexToAddress(i) + sector_header_cleaning_offset,
+ sizeof(KvsSectorHeaderCleaning::sector_clean_order));
+ !status.ok()) {
+ return status;
+ }
next_sector_clean_order_ =
std::max(sector_clean_order_[i] + 1, next_sector_clean_order_);
} else {
@@ -133,9 +147,10 @@
}
if (sector_header_meta.alignment_bytes != alignment_bytes_) {
// NOTE: For now all sectors must have same alignment.
- LOG(ERROR) << "Sector " << i << " has unexpected alignment "
- << alignment_bytes_
- << " != " << sector_header_meta.alignment_bytes;
+ PW_LOG_ERROR("Sector %u has unexpected alignment %u != %u",
+ unsigned(i),
+ unsigned(alignment_bytes_),
+ unsigned(sector_header_meta.alignment_bytes));
return Status::FAILED_PRECONDITION;
}
@@ -154,15 +169,23 @@
// Because underlying flash can be encrypted + erased, trying to readback
// may give random values. It's important to make sure that data is not
// erased before trying to see if there is a token match.
- RETURN_IF_ERROR(partition_.IsChunkErased(
- address, RoundUpForAlignment(sizeof(header)), &is_kvs_header_erased));
- RETURN_IF_ERROR(UnalignedRead(&partition_,
- reinterpret_cast<uint8_t*>(&header),
- address,
- sizeof(header)));
+ if (Status status =
+ partition_.IsChunkErased(address,
+ RoundUpForAlignment(sizeof(header)),
+ &is_kvs_header_erased);
+ !status.ok()) {
+ return status;
+ }
+ if (Status status = UnalignedRead(&partition_,
+ reinterpret_cast<uint8_t*>(&header),
+ address,
+ sizeof(header));
+ !status.ok()) {
+ return status;
+ }
if (is_kvs_header_erased || header.synchronize_token != kChunkSyncValue) {
if (!is_kvs_header_erased) {
- LOG_ERROR("Next sync_token is not clear!");
+ PW_LOG_ERROR("Next sync_token is not clear!");
// TODO: handle this?
}
break; // End of elements in sector
@@ -174,18 +197,24 @@
"nul-terminator.");
// Read key and add to map
- RETURN_IF_ERROR(
- UnalignedRead(&partition_,
- reinterpret_cast<uint8_t*>(&temp_key_buffer_),
- address + RoundUpForAlignment(sizeof(header)),
- header.key_len));
+ if (Status status =
+ UnalignedRead(&partition_,
+ reinterpret_cast<uint8_t*>(&temp_key_buffer_),
+ address + RoundUpForAlignment(sizeof(header)),
+ header.key_len);
+ !status.ok()) {
+ return status;
+ }
temp_key_buffer_[header.key_len] = '\0';
bool is_erased = header.flags & kFlagsIsErasedMask;
KeyIndex index = FindKeyInMap(temp_key_buffer_);
if (index == kListCapacityMax) {
- RETURN_IF_ERROR(AppendToMap(
- temp_key_buffer_, address, header.chunk_len, is_erased));
+ if (Status status = AppendToMap(
+ temp_key_buffer_, address, header.chunk_len, is_erased);
+ !status.ok()) {
+ return status;
+ }
} else if (sector_clean_order_[i] >=
sector_clean_order_[AddressToSectorIndex(
key_map_[index].address)]) {
@@ -202,8 +231,11 @@
clean_not_pending ? partition_.GetSectorSizeBytes() - offset : 0;
}
- LOG_IF_ERROR(EnforceFreeSector())
- << "Failed to force clean at boot, no free sectors available!";
+ if (Status status = EnforceFreeSector(); !status.ok()) {
+ PW_LOG_ERROR(
+ "%s: Failed to force clean at boot, no free sectors available!",
+ status.str());
+ }
enabled_ = true;
return Status::OK;
}
@@ -218,17 +250,17 @@
return Status::INVALID_ARGUMENT;
}
- size_t key_len = util::StringLength(key, kChunkKeyLengthMax + 1u);
+ size_t key_len = string::Length(key, kChunkKeyLengthMax + 1u);
if (key_len == 0 || key_len > kChunkKeyLengthMax) {
return Status::INVALID_ARGUMENT;
}
// TODO: Support unaligned offset reads.
if (offset % alignment_bytes_ != 0) {
- LOG_ERROR("Currently unaligned offsets are not supported");
+ PW_LOG_ERROR("Currently unaligned offsets are not supported");
return Status::INVALID_ARGUMENT;
}
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
if (!enabled_) {
return Status::FAILED_PRECONDITION;
}
@@ -239,35 +271,41 @@
}
KvsHeader header;
// TODO: Could cache the CRC and avoid reading the header.
- RETURN_IF_ERROR(UnalignedRead(&partition_,
- reinterpret_cast<uint8_t*>(&header),
- key_map_[key_index].address,
- sizeof(header)));
+ if (Status status = UnalignedRead(&partition_,
+ reinterpret_cast<uint8_t*>(&header),
+ key_map_[key_index].address,
+ sizeof(header));
+ !status.ok()) {
+ return status;
+ }
if (kChunkSyncValue != header.synchronize_token) {
return Status::DATA_LOSS;
}
if (size + offset > header.chunk_len) {
- LOG_ERROR("Out of bounds read: offset(%u) + size(%u) > data_size(%u)",
- offset,
- size,
- header.chunk_len);
+ PW_LOG_ERROR("Out of bounds read: offset(%u) + size(%u) > data_size(%u)",
+ offset,
+ size,
+ header.chunk_len);
return Status::INVALID_ARGUMENT;
}
- RETURN_IF_ERROR(UnalignedRead(
- &partition_,
- value,
- key_map_[key_index].address + RoundUpForAlignment(sizeof(KvsHeader)) +
- RoundUpForAlignment(header.key_len) + offset,
- size));
+ if (Status status = UnalignedRead(
+ &partition_,
+ value,
+ key_map_[key_index].address + RoundUpForAlignment(sizeof(KvsHeader)) +
+ RoundUpForAlignment(header.key_len) + offset,
+ size);
+ !status.ok()) {
+ return status;
+ }
// Verify CRC only when full packet was read.
if (offset == 0 && size == header.chunk_len) {
uint16_t crc = CalculateCrc(key, key_len, value, size);
if (crc != header.crc) {
- LOG_ERROR("KVS CRC does not match for key=%s [expected %u, found %u]",
- key,
- header.crc,
- crc);
+ PW_LOG_ERROR("KVS CRC does not match for key=%s [expected %u, found %u]",
+ key,
+ header.crc,
+ crc);
return Status::DATA_LOSS;
}
}
@@ -278,9 +316,8 @@
uint16_t key_size,
const uint8_t* value,
uint16_t value_size) const {
- CcittCrc16 crc;
- crc.AppendBytes(ConstBuffer(reinterpret_cast<const uint8_t*>(key), key_size));
- return crc.AppendBytes(ConstBuffer(value, value_size));
+ uint16_t crc = checksum::CcittCrc16(as_bytes(span(key, key_size)));
+ return checksum::CcittCrc16(as_bytes(span(value, value_size)), crc);
}
Status KeyValueStore::CalculateCrcFromValueAddress(
@@ -289,15 +326,17 @@
FlashPartition::Address value_address,
uint16_t value_size,
uint16_t* crc_ret) {
- CcittCrc16 crc;
- crc.AppendBytes(ConstBuffer(reinterpret_cast<const uint8_t*>(key), key_size));
+ uint16_t crc = checksum::CcittCrc16(as_bytes(span(key, key_size)));
for (size_t i = 0; i < value_size; i += TempBufferAlignedSize()) {
auto read_size = std::min(value_size - i, TempBufferAlignedSize());
- RETURN_IF_ERROR(
- UnalignedRead(&partition_, temp_buffer_, value_address + i, read_size));
- crc.AppendBytes(ConstBuffer(temp_buffer_, read_size));
+ if (Status status = UnalignedRead(
+ &partition_, temp_buffer_, value_address + i, read_size);
+ !status.ok()) {
+ return status;
+ }
+ crc = checksum::CcittCrc16(as_bytes(span(temp_buffer_, read_size)));
}
- *crc_ret = crc.CurrentValue();
+ *crc_ret = crc;
return Status::OK;
}
@@ -309,13 +348,13 @@
return Status::INVALID_ARGUMENT;
}
- size_t key_len = util::StringLength(key, (kChunkKeyLengthMax + 1u));
+ size_t key_len = string::Length(key, kChunkKeyLengthMax + 1u);
if (key_len == 0 || key_len > kChunkKeyLengthMax ||
size > kChunkValueLengthMax) {
return Status::INVALID_ARGUMENT;
}
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
if (!enabled_) {
return Status::FAILED_PRECONDITION;
}
@@ -333,7 +372,9 @@
// Check if this would use the last empty sector on KVS with multiple sectors
if (SectorCount() > 1 && IsInLastFreeSector(address)) {
// Forcing a full garbage collect to free more sectors.
- RETURN_IF_ERROR(FullGarbageCollect());
+ if (Status status = FullGarbageCollect(); !status.ok()) {
+ return status;
+ }
address = FindSpace(ChunkSize(key_len, size));
if (address == kSectorInvalid || IsInLastFreeSector(address)) {
// Couldn't find space, KVS is full.
@@ -341,8 +382,12 @@
}
}
- RETURN_IF_ERROR(WriteKeyValue(address, key, value, size));
- RETURN_IF_ERROR(AppendToMap(key, address, size));
+ if (Status status = WriteKeyValue(address, key, value, size); !status.ok()) {
+ return status;
+ }
+ if (Status status = AppendToMap(key, address, size); !status.ok()) {
+ return status;
+ }
return Status::OK;
}
@@ -362,7 +407,9 @@
if (clean_pending_sectors ==
(sector_clean_order_[sector] != kSectorCleanNotPending)) {
if (!clean_pending_sectors) {
- RETURN_IF_ERROR(MarkSectorForClean(sector));
+ if (Status status = MarkSectorForClean(sector); !status.ok()) {
+ return status;
+ }
}
Status status = CleanSector(sector);
if (!status.ok() && status != Status::RESOURCE_EXHAUSTED) {
@@ -380,22 +427,31 @@
if (SectorCount() == 1 || HasEmptySector()) {
return Status::OK;
}
- LOG_INFO("KVS garbage collecting to get a free sector");
- RETURN_IF_ERROR(GarbageCollectImpl(true /*clean_pending_sectors*/,
- true /*exit_when_have_free_sector*/));
+ PW_LOG_INFO("KVS garbage collecting to get a free sector");
+ if (Status status = GarbageCollectImpl(true /*clean_pending_sectors*/,
+ true /*exit_when_have_free_sector*/);
+ !status.ok()) {
+ return status;
+ }
if (HasEmptySector()) {
return Status::OK;
}
- LOG_INFO("KVS: trying to clean non-pending sectors for more space");
- RETURN_IF_ERROR(GarbageCollectImpl(false /*clean_pending_sectors*/,
- true /*exit_when_have_free_sector*/));
+ PW_LOG_INFO("KVS: trying to clean non-pending sectors for more space");
+ if (Status status = GarbageCollectImpl(false /*clean_pending_sectors*/,
+ true /*exit_when_have_free_sector*/);
+ !status.ok()) {
+ return status;
+ }
return HaveEmptySectorImpl() ? Status::OK : Status::RESOURCE_EXHAUSTED;
}
Status KeyValueStore::FullGarbageCollect() {
- LOG_INFO("KVS: Full garbage collecting to try to free space");
- RETURN_IF_ERROR(GarbageCollectImpl(true /*clean_pending_sectors*/,
- false /*exit_when_have_free_sector*/));
+ PW_LOG_INFO("KVS: Full garbage collecting to try to free space");
+ if (Status status = GarbageCollectImpl(true /*clean_pending_sectors*/,
+ false /*exit_when_have_free_sector*/);
+ !status.ok()) {
+ return status;
+ }
return GarbageCollectImpl(false /*clean_pending_sectors*/,
false /*exit_when_have_free_sector*/);
}
@@ -410,8 +466,10 @@
}
size_t key_length =
- util::StringLength(key_map_[key_index].key, (kChunkKeyLengthMax + 1u));
- RETURN_STATUS_IF(key_length > kChunkKeyLengthMax, Status::INTERNAL);
+ string::Length(key_map_[key_index].key, kChunkKeyLengthMax + 1u);
+ if (key_length > kChunkKeyLengthMax) {
+ return Status::INTERNAL;
+ }
uint32_t space_required = ChunkSize(key_length, size);
SectorIndex sector = AddressToSectorIndex(key_map_[key_index].address);
@@ -424,14 +482,19 @@
sector_space_remaining;
} else {
// No space in current sector, mark sector for clean and use another sector.
- RETURN_IF_ERROR(MarkSectorForClean(sector));
+ if (Status status = MarkSectorForClean(sector); !status.ok()) {
+ return status;
+ }
address = FindSpace(ChunkSize(key_length, size));
}
if (address == kSectorInvalid) {
return Status::RESOURCE_EXHAUSTED;
}
- RETURN_IF_ERROR(
- WriteKeyValue(address, key_map_[key_index].key, value, size, is_erased));
+ if (Status status = WriteKeyValue(
+ address, key_map_[key_index].key, value, size, is_erased);
+ !status.ok()) {
+ return status;
+ }
UpdateMap(key_index, address, size, is_erased);
return EnforceFreeSector();
@@ -451,7 +514,7 @@
key_map_[index].address,
sizeof(header));
uint8_t key_len =
- util::StringLength(key_map_[index].key, (kChunkKeyLengthMax + 1u));
+ string::Length(key_map_[index].key, kChunkKeyLengthMax + 1u);
if (key_len > kChunkKeyLengthMax) {
return false;
}
@@ -477,7 +540,7 @@
auto status =
UnalignedRead(&partition_, temp_buffer_, address + i, read_size);
if (!status.ok()) {
- LOG(ERROR) << "Failed to read chunk: " << status;
+ PW_LOG_ERROR("Failed to read chunk: %s", status.str());
return false;
}
if (memcmp(value + i, temp_buffer_, read_size) != 0) {
@@ -492,11 +555,11 @@
return Status::INVALID_ARGUMENT;
}
- size_t key_len = util::StringLength(key, (kChunkKeyLengthMax + 1u));
+ size_t key_len = string::Length(key, kChunkKeyLengthMax + 1u);
if (key_len == 0 || key_len > kChunkKeyLengthMax) {
return Status::INVALID_ARGUMENT;
}
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
if (!enabled_) {
return Status::FAILED_PRECONDITION;
}
@@ -525,10 +588,14 @@
return status;
}
- RETURN_IF_ERROR(PaddedWrite(&partition_,
- SectorIndexToAddress(sector_index),
- reinterpret_cast<const uint8_t*>(§or_header),
- sizeof(sector_header)));
+ if (Status status =
+ PaddedWrite(&partition_,
+ SectorIndexToAddress(sector_index),
+ reinterpret_cast<const uint8_t*>(§or_header),
+ sizeof(sector_header));
+ !status.ok()) {
+ return status;
+ }
// Update space remaining
sector_clean_order_[sector_index] = kSectorCleanNotPending;
@@ -541,8 +608,10 @@
const uint8_t* value,
uint16_t size,
bool is_erased) {
- uint16_t key_length = util::StringLength(key, (kChunkKeyLengthMax + 1u));
- RETURN_STATUS_IF(key_length > kChunkKeyLengthMax, Status::INTERNAL);
+ uint16_t key_length = string::Length(key, kChunkKeyLengthMax + 1u);
+ if (key_length > kChunkKeyLengthMax) {
+ return Status::INTERNAL;
+ }
constexpr uint16_t kFlagDefaultValue = 0;
KvsHeader header = {
@@ -553,16 +622,26 @@
.chunk_len = size};
SectorIndex sector = AddressToSectorIndex(address);
- RETURN_IF_ERROR(PaddedWrite(&partition_,
- address,
- reinterpret_cast<uint8_t*>(&header),
- sizeof(header)));
+ if (Status status = PaddedWrite(&partition_,
+ address,
+ reinterpret_cast<uint8_t*>(&header),
+ sizeof(header));
+ !status.ok()) {
+ return status;
+ }
address += RoundUpForAlignment(sizeof(header));
- RETURN_IF_ERROR(PaddedWrite(
- &partition_, address, reinterpret_cast<const uint8_t*>(key), key_length));
+ if (Status status = PaddedWrite(&partition_,
+ address,
+ reinterpret_cast<const uint8_t*>(key),
+ key_length);
+ !status.ok()) {
+ }
address += RoundUpForAlignment(key_length);
if (size > 0) {
- RETURN_IF_ERROR(PaddedWrite(&partition_, address, value, size));
+ if (Status status = PaddedWrite(&partition_, address, value, size);
+ !status.ok()) {
+ return status;
+ }
}
sector_space_remaining_[sector] -= ChunkSize(key_length, size);
return Status::OK;
@@ -579,9 +658,16 @@
for (size_t i = 0; i < size; i += TempBufferAlignedSize()) {
size_t move_size = std::min(size - i, TempBufferAlignedSize());
DCHECK_EQ(move_size % alignment_bytes_, 0);
- RETURN_IF_ERROR(partition_.Read(temp_buffer_, src_address + i, move_size));
- RETURN_IF_ERROR(
- partition_.Write(dest_address + i, temp_buffer_, move_size));
+ if (Status status =
+ partition_.Read(temp_buffer_, src_address + i, move_size);
+ !status.ok()) {
+ return status;
+ }
+ if (Status status =
+ partition_.Write(dest_address + i, temp_buffer_, move_size);
+ !status.ok()) {
+ return status;
+ }
}
return Status::OK;
}
@@ -594,12 +680,15 @@
// Flag the sector as clean being active. This ensures we can handle losing
// power while a clean is active.
const KvsSectorHeaderCleaning kValue = {next_sector_clean_order_};
- RETURN_IF_ERROR(
- PaddedWrite(&partition_,
- SectorIndexToAddress(sector) +
- RoundUpForAlignment(sizeof(KvsSectorHeaderMeta)),
- reinterpret_cast<const uint8_t*>(&kValue),
- sizeof(kValue)));
+ if (Status status =
+ PaddedWrite(&partition_,
+ SectorIndexToAddress(sector) +
+ RoundUpForAlignment(sizeof(KvsSectorHeaderMeta)),
+ reinterpret_cast<const uint8_t*>(&kValue),
+ sizeof(kValue));
+ !status.ok()) {
+ return status;
+ }
sector_space_remaining_[sector] = 0;
sector_clean_order_[sector] = next_sector_clean_order_;
next_sector_clean_order_++;
@@ -621,14 +710,17 @@
if (i < map_size_ && sector == AddressToSectorIndex(key_map_[i].address)) {
uint8_t key_len =
- util::StringLength(key_map_[i].key, (kChunkKeyLengthMax + 1u));
+ string::Length(key_map_[i].key, kChunkKeyLengthMax + 1u);
FlashPartition::Address address = key_map_[i].address;
auto size = ChunkSize(key_len, key_map_[i].chunk_len);
FlashPartition::Address move_address = FindSpace(size);
if (move_address == kSectorInvalid) {
return Status::RESOURCE_EXHAUSTED;
}
- RETURN_IF_ERROR(MoveChunk(move_address, address, size));
+ if (Status status = MoveChunk(move_address, address, size);
+ !status.ok()) {
+ return status;
+ }
sector_space_remaining_[AddressToSectorIndex(move_address)] -= size;
key_map_[i].address = move_address; // Update map
}
@@ -641,7 +733,7 @@
if (all_sectors_have_been_cleaned == nullptr) {
return Status::INVALID_ARGUMENT;
}
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
bool have_cleaned_sector = false;
for (SectorIndex sector = 0; sector < SectorCount(); sector++) {
if (sector_clean_order_[sector] != kSectorCleanNotPending) {
@@ -649,7 +741,9 @@
*all_sectors_have_been_cleaned = false;
return Status::OK;
}
- RETURN_IF_ERROR(CleanSector(sector));
+ if (Status status = CleanSector(sector); !status.ok()) {
+ return status;
+ }
have_cleaned_sector = true;
}
}
@@ -660,7 +754,9 @@
Status KeyValueStore::CleanAllInternal() {
for (SectorIndex sector = 0; sector < SectorCount(); sector++) {
if (sector_clean_order_[sector] != kSectorCleanNotPending) {
- RETURN_IF_ERROR(CleanSector(sector));
+ if (Status status = CleanSector(sector); !status.ok()) {
+ return status;
+ }
}
}
return Status::OK;
@@ -703,11 +799,11 @@
return Status::INVALID_ARGUMENT;
}
- size_t key_len = util::StringLength(key, (kChunkKeyLengthMax + 1u));
+ size_t key_len = string::Length(key, kChunkKeyLengthMax + 2u);
if (key_len == 0 || key_len > kChunkKeyLengthMax) {
return Status::INVALID_ARGUMENT;
}
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
if (!enabled_) {
return Status::FAILED_PRECONDITION;
}
@@ -725,17 +821,17 @@
uint16_t chunk_len,
bool is_erased) {
if (map_size_ >= kListCapacityMax) {
- LOG_ERROR("Can't add: reached max supported keys %d", kListCapacityMax);
+ PW_LOG_ERROR("Can't add: reached max supported keys %d", kListCapacityMax);
return Status::INTERNAL;
}
// Copy incoming key into map entry, ensuring size checks and nul-termination.
- StringBuilder key_builder(key_map_[map_size_].key,
- sizeof(key_map_[map_size_].key));
+ StringBuilder key_builder(
+ span(key_map_[map_size_].key, sizeof(key_map_[map_size_].key)));
key_builder.append(key);
if (!key_builder.status().ok()) {
- LOG_ERROR("Can't add: got invalid key: %s!", key_builder.status().str());
+ PW_LOG_ERROR("Can't add: got invalid key: %s!", key_builder.status().str());
return Status::INTERNAL;
}
@@ -802,4 +898,4 @@
return 0;
}
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/key_value_store_sub_sector_test.cc b/pw_kvs/key_value_store_sub_sector_test.cc
index ff908f5..0e13167 100644
--- a/pw_kvs/key_value_store_sub_sector_test.cc
+++ b/pw_kvs/key_value_store_sub_sector_test.cc
@@ -12,34 +12,29 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_kvs/key_value_store.h"
-
+#include "gtest/gtest.h"
#include "pw_kvs/assert.h"
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/platform/board.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/test/fixture.h"
-#include "pw_kvs/test/framework.h"
-#include "pw_kvs/test/status_macros.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_kvs/key_value_store.h"
+#include "pw_status/status.h"
+
+#define USE_MEMORY_BUFFER 1
#if USE_MEMORY_BUFFER
-#include "pw_kvs/test/fakes/in_memory_fake_flash.h"
+#include "pw_kvs/in_memory_fake_flash.h"
#endif // USE_MEMORY_BUFFER
-namespace pw {
+namespace pw::kvs {
namespace {
#if USE_MEMORY_BUFFER
InMemoryFakeFlash<1024, 4> test_flash(8); // 4 x 1k sectors, 8 byte alignment
FlashPartition test_partition(&test_flash, 0, test_flash.GetSectorCount());
-// Test KVS against FlashSubSector
-FlashMemorySubSector test_subsector_flash(&test_flash,
- 0,
- 128); // Expose less than a sector.
-#else // Device test
-FlashPartition& test_partition = Board::Instance().FlashExternalTestPartition();
-FlashMemorySubSector& test_subsector_flash =
- Board::Instance().FlashMemorySubSectorTestChunk();
+// Test KVS against FlashSubSector. Expose less than a sector.
+FlashMemorySubSector test_subsector_flash(&test_flash, 0, 128);
+#else // TODO: Test with real flash
+FlashPartition& test_partition = FlashExternalTestPartition();
+FlashMemorySubSector& test_subsector_flash = FlashMemorySubSectorTestChunk();
#endif // USE_MEMORY_BUFFER
FlashPartition test_subsector_partition(&test_subsector_flash, 0, 1);
@@ -53,41 +48,45 @@
// The subsector region is assumed to be a part of the test partition.
// In order to clear state before the test, we must erase the entire test
// partition because erase operations are disallowed on FlashMemorySubSectors.
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// Reset KVS
subsector_kvs.Disable();
- ASSERT_OK(subsector_kvs.Enable());
+ ASSERT_EQ(Status::OK, subsector_kvs.Enable());
// Add some data
uint8_t value1 = 0xDA;
- ASSERT_OK(subsector_kvs.Put(keys[0], &value1, sizeof(value1)));
+ ASSERT_EQ(Status::OK, subsector_kvs.Put(keys[0], &value1, sizeof(value1)));
uint32_t value2 = 0xBAD0301f;
- ASSERT_OK(subsector_kvs.Put(
- keys[1], reinterpret_cast<uint8_t*>(&value2), sizeof(value2)));
+ ASSERT_EQ(Status::OK,
+ subsector_kvs.Put(
+ keys[1], reinterpret_cast<uint8_t*>(&value2), sizeof(value2)));
// Verify data
uint32_t test2;
- EXPECT_OK(subsector_kvs.Get(
- keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+ EXPECT_EQ(Status::OK,
+ subsector_kvs.Get(
+ keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
uint8_t test1;
- ASSERT_OK(subsector_kvs.Get(
- keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)));
+ ASSERT_EQ(Status::OK,
+ subsector_kvs.Get(
+ keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)));
EXPECT_EQ(test1, value1);
// Erase a key
- ASSERT_OK(subsector_kvs.Erase(keys[0]));
+ ASSERT_EQ(Status::OK, subsector_kvs.Erase(keys[0]));
// Verify it was erased
- EXPECT_EQ(subsector_kvs
- .Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1))
- .code(),
+ EXPECT_EQ(subsector_kvs.Get(
+ keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)),
Status::NOT_FOUND);
test2 = 0;
- ASSERT_OK(subsector_kvs.Get(
- keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+ ASSERT_EQ(Status::OK,
+ subsector_kvs.Get(
+ keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
EXPECT_EQ(test2, value2);
// Erase other key
@@ -101,11 +100,12 @@
// The subsector region is assumed to be a part of the test partition.
// In order to clear state before the test, we must erase the entire test
// partition because erase operations are disallowed on FlashMemorySubSectors.
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// Reset KVS
subsector_kvs.Disable();
- ASSERT_OK(subsector_kvs.Enable());
+ ASSERT_EQ(Status::OK, subsector_kvs.Enable());
// Store as much data as possible in the KVS until it fills up.
uint64_t test = 0;
@@ -123,8 +123,8 @@
// Even though we failed to fill the KVS, it still works, and we
// should have the previous test value as the most recent value in the KVS.
uint64_t value = 0;
- ASSERT_OK(subsector_kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, subsector_kvs.Get(keys[0], &value));
EXPECT_EQ(test - 1, value);
}
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/key_value_store_test.cc b/pw_kvs/key_value_store_test.cc
index fa5eaf9..92bc6a5 100644
--- a/pw_kvs/key_value_store_test.cc
+++ b/pw_kvs/key_value_store_test.cc
@@ -14,21 +14,22 @@
#include "pw_kvs/key_value_store.h"
+#include "pw_span/span.h"
+
+#define USE_MEMORY_BUFFER 1
+
+#include "gtest/gtest.h"
+#include "pw_checksum/ccitt_crc16.h"
#include "pw_kvs/assert.h"
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/os/stack_checks.h"
-#include "pw_kvs/platform/board.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/test/fixture.h"
-#include "pw_kvs/test/framework.h"
-#include "pw_kvs/test/status_macros.h"
-#include "pw_kvs/util/ccitt_crc16.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
+#include "pw_string/util.h"
#if USE_MEMORY_BUFFER
-#include "pw_kvs/test/fakes/in_memory_fake_flash.h"
+#include "pw_kvs/in_memory_fake_flash.h"
#endif // USE_MEMORY_BUFFER
-namespace pw {
+namespace pw::kvs {
namespace {
#if USE_MEMORY_BUFFER
@@ -41,8 +42,8 @@
FlashPartition large_test_partition(&large_test_flash,
0,
large_test_flash.GetSectorCount());
-#else // Device test
-FlashPartition& test_partition = Board::Instance().FlashExternalTestPartition();
+#else // TODO: Test with real flash
+FlashPartition& test_partition = FlashExternalTestPartition();
#endif // USE_MEMORY_BUFFER
KeyValueStore kvs(&test_partition);
@@ -65,13 +66,19 @@
static constexpr uint16_t kMaxAlignmentBytes = 128;
uint8_t alignment_buffer[kMaxAlignmentBytes] = {0};
uint16_t aligned_bytes = size - (size % partition->GetAlignmentBytes());
- RETURN_IF_ERROR(partition->Write(address, buf, aligned_bytes));
+ if (Status status = partition->Write(address, buf, aligned_bytes);
+ !status.ok()) {
+ return status;
+ }
uint16_t remaining_bytes = size - aligned_bytes;
if (remaining_bytes > 0) {
memcpy(alignment_buffer, &buf[aligned_bytes], remaining_bytes);
- RETURN_IF_ERROR(partition->Write(address + aligned_bytes,
- alignment_buffer,
- partition->GetAlignmentBytes()));
+ if (Status status = partition->Write(address + aligned_bytes,
+ alignment_buffer,
+ partition->GetAlignmentBytes());
+ !status.ok()) {
+ return status;
+ }
}
return Status::OK;
}
@@ -138,51 +145,51 @@
memset(buffer.data(), 0, buffer.size());
while (size_to_fill > 0) {
buffer[0]++; // Changing buffer value so put actually does something
- ASSERT_OK(
+ ASSERT_EQ(
+ Status::OK,
kvs.Put(key,
buffer.data(),
chunk_len - kvs_attr.ChunkHeaderSize() - kvs_attr.KeySize()));
size_to_fill -= chunk_len;
chunk_len = std::min(size_to_fill, kMaxPutSize);
}
- ASSERT_OK(kvs.Erase(key));
+ ASSERT_EQ(Status::OK, kvs.Erase(key));
}
uint16_t CalcKvsCrc(const char* key, const void* data, size_t data_len) {
- CcittCrc16 crc;
static constexpr size_t kChunkKeyLengthMax = 15;
- crc.AppendBytes(
- ConstBuffer(reinterpret_cast<const uint8_t*>(key),
- pw::util::StringLength(key, kChunkKeyLengthMax)));
- return crc.AppendBytes(
- ConstBuffer(reinterpret_cast<const uint8_t*>(data), data_len));
+ uint16_t crc = checksum::CcittCrc16(
+ as_bytes(span(key, string::Length(key, kChunkKeyLengthMax))));
+ return checksum::CcittCrc16(
+ span(static_cast<const std::byte*>(data), data_len), crc);
}
uint16_t CalcTestPartitionCrc() {
uint8_t buf[16]; // Read as 16 byte chunks
CHECK_EQ(sizeof(buf) % test_partition.GetAlignmentBytes(), 0);
CHECK_EQ(test_partition.GetSizeBytes() % sizeof(buf), 0);
- CcittCrc16 crc;
+ uint16_t crc = checksum::kCcittCrc16DefaultInitialValue;
for (size_t i = 0; i < test_partition.GetSizeBytes(); i += sizeof(buf)) {
test_partition.Read(buf, i, sizeof(buf));
- crc.AppendBytes(ConstBuffer(buf, sizeof(buf)));
+ crc = checksum::CcittCrc16(as_bytes(span(buf)), crc);
}
- return crc.CurrentValue();
+ return crc;
}
} // namespace
TEST_F(KeyValueStoreTest, FuzzTest) {
if (test_partition.GetSectorSizeBytes() < 4 * 1024 ||
test_partition.GetSectorCount() < 4) {
- LOG_INFO("Sectors too small, skipping test.");
+ PW_LOG_INFO("Sectors too small, skipping test.");
return; // TODO: Test could be generalized
}
// Erase
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
const char* key1 = "Buf1";
const char* key2 = "Buf2";
const size_t kLargestBufSize = 3 * 1024;
@@ -192,10 +199,10 @@
memset(buf2, 2, sizeof(buf2));
// Start with things in KVS
- ASSERT_OK(kvs.Put(key1, buf1, sizeof(buf1)));
- ASSERT_OK(kvs.Put(key2, buf2, sizeof(buf2)));
+ ASSERT_EQ(Status::OK, kvs.Put(key1, buf1, sizeof(buf1)));
+ ASSERT_EQ(Status::OK, kvs.Put(key2, buf2, sizeof(buf2)));
for (size_t j = 0; j < keys.size(); j++) {
- ASSERT_OK(kvs.Put(keys[j], j));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[j], j));
}
for (size_t i = 0; i < 100; i++) {
@@ -204,29 +211,29 @@
size_t size2 = (kLargestBufSize) / (100 - i);
for (size_t j = 0; j < 50; j++) {
// Rewrite a single key many times, can fill up a sector
- ASSERT_OK(kvs.Put("some_data", j));
+ ASSERT_EQ(Status::OK, kvs.Put("some_data", j));
}
// Delete and re-add everything
- ASSERT_OK(kvs.Erase(key1));
- ASSERT_OK(kvs.Put(key1, buf1, size1));
- ASSERT_OK(kvs.Erase(key2));
- ASSERT_OK(kvs.Put(key2, buf2, size2));
+ ASSERT_EQ(Status::OK, kvs.Erase(key1));
+ ASSERT_EQ(Status::OK, kvs.Put(key1, buf1, size1));
+ ASSERT_EQ(Status::OK, kvs.Erase(key2));
+ ASSERT_EQ(Status::OK, kvs.Put(key2, buf2, size2));
for (size_t j = 0; j < keys.size(); j++) {
- ASSERT_OK(kvs.Erase(keys[j]));
- ASSERT_OK(kvs.Put(keys[j], j));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[j]));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[j], j));
}
// Re-enable and verify
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
static uint8_t buf[4 * 1024];
- ASSERT_OK(kvs.Get(key1, buf, size1));
+ ASSERT_EQ(Status::OK, kvs.Get(key1, buf, size1));
ASSERT_EQ(memcmp(buf, buf1, size1), 0);
- ASSERT_OK(kvs.Get(key2, buf, size2));
+ ASSERT_EQ(Status::OK, kvs.Get(key2, buf, size2));
ASSERT_EQ(memcmp(buf2, buf2, size2), 0);
for (size_t j = 0; j < keys.size(); j++) {
size_t ret = 1000;
- ASSERT_OK(kvs.Get(keys[j], &ret));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[j], &ret));
ASSERT_EQ(ret, j);
}
}
@@ -234,40 +241,44 @@
TEST_F(KeyValueStoreTest, Basic) {
// Erase
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Add some data
uint8_t value1 = 0xDA;
- ASSERT_OK(kvs.Put(keys[0], &value1, sizeof(value1)));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], &value1, sizeof(value1)));
uint32_t value2 = 0xBAD0301f;
- ASSERT_OK(
+ ASSERT_EQ(
+ Status::OK,
kvs.Put(keys[1], reinterpret_cast<uint8_t*>(&value2), sizeof(value2)));
// Verify data
uint32_t test2;
- EXPECT_OK(
+ EXPECT_EQ(
+ Status::OK,
kvs.Get(keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
uint8_t test1;
- ASSERT_OK(
+ ASSERT_EQ(
+ Status::OK,
kvs.Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)));
EXPECT_EQ(test1, value1);
EXPECT_EQ(test2, value2);
// Erase a key
- EXPECT_OK(kvs.Erase(keys[0]));
+ EXPECT_EQ(Status::OK, kvs.Erase(keys[0]));
// Verify it was erased
- EXPECT_EQ(kvs.Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1))
- .code(),
+ EXPECT_EQ(kvs.Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)),
Status::NOT_FOUND);
test2 = 0;
- ASSERT_OK(
+ ASSERT_EQ(
+ Status::OK,
kvs.Get(keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
EXPECT_EQ(test2, value2);
@@ -280,27 +291,28 @@
TEST_F(KeyValueStoreTest, MaxKeyLength) {
// Erase
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Add some data
char key[16] = "123456789abcdef"; // key length 15 (without \0)
int value = 1;
- ASSERT_OK(kvs.Put(key, value));
+ ASSERT_EQ(Status::OK, kvs.Put(key, value));
// Verify data
int test = 0;
- ASSERT_OK(kvs.Get(key, &test));
+ ASSERT_EQ(Status::OK, kvs.Get(key, &test));
EXPECT_EQ(test, value);
// Erase a key
kvs.Erase(key);
// Verify it was erased
- EXPECT_EQ(kvs.Get(key, &test).code(), Status::NOT_FOUND);
+ EXPECT_EQ(kvs.Get(key, &test), Status::NOT_FOUND);
}
TEST_F(KeyValueStoreTest, LargeBuffers) {
@@ -321,21 +333,22 @@
const size_t kAvailSectorSpace = test_partition.GetSectorSizeBytes() *
(test_partition.GetSectorCount() - 1);
if (kAvailSectorSpace < kMinSize) {
- LOG_INFO("KVS too small, skipping test.");
+ PW_LOG_INFO("KVS too small, skipping test.");
return;
}
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Add and verify
for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
memset(buffer.data(), add_idx, buffer.size());
- ASSERT_OK(kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
EXPECT_EQ(kvs.KeyCount(), add_idx + 1);
for (unsigned verify_idx = 0; verify_idx <= add_idx; verify_idx++) {
memset(buffer.data(), 0, buffer.size());
- ASSERT_OK(kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK,
+ kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
for (unsigned i = 0; i < buffer.size(); i++) {
EXPECT_EQ(buffer[i], verify_idx);
}
@@ -344,16 +357,16 @@
// Erase and verify
for (unsigned erase_idx = 0; erase_idx < keys.size(); erase_idx++) {
- ASSERT_OK(kvs.Erase(keys[erase_idx]));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[erase_idx]));
EXPECT_EQ(kvs.KeyCount(), keys.size() - erase_idx - 1);
for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
memset(buffer.data(), 0, buffer.size());
if (verify_idx <= erase_idx) {
- ASSERT_EQ(
- kvs.Get(keys[verify_idx], buffer.data(), buffer.size()).code(),
- Status::NOT_FOUND);
+ ASSERT_EQ(kvs.Get(keys[verify_idx], buffer.data(), buffer.size()),
+ Status::NOT_FOUND);
} else {
- ASSERT_OK(kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK,
+ kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
for (uint32_t i = 0; i < buffer.size(); i++) {
EXPECT_EQ(buffer[i], verify_idx);
}
@@ -377,39 +390,40 @@
const size_t kAvailSectorSpace = test_partition.GetSectorSizeBytes() *
(test_partition.GetSectorCount() - 1);
if (kAvailSectorSpace < kMinSize) {
- LOG_INFO("KVS too small, skipping test.");
+ PW_LOG_INFO("KVS too small, skipping test.");
return;
}
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Add some items
for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
memset(buffer.data(), add_idx, buffer.size());
- ASSERT_OK(kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
EXPECT_EQ(kvs.KeyCount(), add_idx + 1);
}
// Enable different KVS which should be able to properly setup the same map
// from what is stored in flash.
- ASSERT_OK(kvs_local_.Enable());
+ ASSERT_EQ(Status::OK, kvs_local_.Enable());
EXPECT_EQ(kvs_local_.KeyCount(), keys.size());
// Ensure adding to new KVS works
uint8_t value = 0xDA;
const char* key = "new_key";
- ASSERT_OK(kvs_local_.Put(key, &value, sizeof(value)));
+ ASSERT_EQ(Status::OK, kvs_local_.Put(key, &value, sizeof(value)));
uint8_t test;
- ASSERT_OK(kvs_local_.Get(key, &test, sizeof(test)));
+ ASSERT_EQ(Status::OK, kvs_local_.Get(key, &test, sizeof(test)));
EXPECT_EQ(value, test);
EXPECT_EQ(kvs_local_.KeyCount(), keys.size() + 1);
// Verify previous data
for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
memset(buffer.data(), 0, buffer.size());
- ASSERT_OK(kvs_local_.Get(keys[verify_idx], buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK,
+ kvs_local_.Get(keys[verify_idx], buffer.data(), buffer.size()));
for (uint32_t i = 0; i < buffer.size(); i++) {
EXPECT_EQ(buffer[i], verify_idx);
}
@@ -421,18 +435,18 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Calculate number of elements to ensure multiple sectors are required.
uint16_t add_count =
(test_partition.GetSectorSizeBytes() / buffer.size()) + 1;
if (kvs.GetMaxKeys() < add_count) {
- LOG_INFO("Sector size too large, skipping test.");
+ PW_LOG_INFO("Sector size too large, skipping test.");
return; // this chip has very large sectors, test won't work
}
if (test_partition.GetSectorCount() < 3) {
- LOG_INFO("Not enough sectors, skipping test.");
+ PW_LOG_INFO("Not enough sectors, skipping test.");
return; // need at least 3 sectors for multi-sector test
}
@@ -440,14 +454,14 @@
for (unsigned add_idx = 0; add_idx < add_count; add_idx++) {
memset(buffer.data(), add_idx, buffer.size());
snprintf(key, sizeof(key), "key_%u", add_idx);
- ASSERT_OK(kvs.Put(key, buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK, kvs.Put(key, buffer.data(), buffer.size()));
EXPECT_EQ(kvs.KeyCount(), add_idx + 1);
}
for (unsigned verify_idx = 0; verify_idx < add_count; verify_idx++) {
memset(buffer.data(), 0, buffer.size());
snprintf(key, sizeof(key), "key_%u", verify_idx);
- ASSERT_OK(kvs.Get(key, buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK, kvs.Get(key, buffer.data(), buffer.size()));
for (uint32_t i = 0; i < buffer.size(); i++) {
EXPECT_EQ(buffer[i], verify_idx);
}
@@ -456,7 +470,7 @@
// Check erase
for (unsigned erase_idx = 0; erase_idx < add_count; erase_idx++) {
snprintf(key, sizeof(key), "key_%u", erase_idx);
- ASSERT_OK(kvs.Erase(key));
+ ASSERT_EQ(Status::OK, kvs.Erase(key));
EXPECT_EQ(kvs.KeyCount(), add_count - erase_idx - 1);
}
}
@@ -466,24 +480,26 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Write first value
const uint8_t kValue1 = 0xDA;
const uint8_t kValue2 = 0x12;
const char* key = "the_key";
- ASSERT_OK(kvs.Put(key, &kValue1, sizeof(kValue1)));
+ ASSERT_EQ(Status::OK, kvs.Put(key, &kValue1, sizeof(kValue1)));
// Verify
uint8_t value;
- ASSERT_OK(kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
+ ASSERT_EQ(Status::OK,
+ kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
EXPECT_EQ(kValue1, value);
// Write new value for key
- ASSERT_OK(kvs.Put(key, &kValue2, sizeof(kValue2)));
+ ASSERT_EQ(Status::OK, kvs.Put(key, &kValue2, sizeof(kValue2)));
// Verify
- ASSERT_OK(kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
+ ASSERT_EQ(Status::OK,
+ kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
EXPECT_EQ(kValue2, value);
// Verify only 1 element exists
@@ -495,7 +511,7 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
const char* key = "the_key";
constexpr uint8_t kReadSize = 16; // needs to be a multiple of alignment
@@ -507,13 +523,14 @@
for (uint8_t i = 0; i < kTestBufferSize; i++) {
buffer[i] = i;
}
- ASSERT_OK(kvs.Put(key, buffer.data(), kTestBufferSize));
+ ASSERT_EQ(Status::OK, kvs.Put(key, buffer.data(), kTestBufferSize));
EXPECT_EQ(kvs.KeyCount(), 1);
// Read in small chunks and verify
for (int i = 0; i < kTestBufferSize / kReadSize; i++) {
memset(buffer.data(), 0, buffer.size());
- ASSERT_OK(kvs.Get(key, buffer.data(), kReadSize, i * kReadSize));
+ ASSERT_EQ(Status::OK,
+ kvs.Get(key, buffer.data(), kReadSize, i * kReadSize));
for (unsigned j = 0; j < kReadSize; j++) {
ASSERT_EQ(buffer[j], j + i * kReadSize);
}
@@ -526,7 +543,7 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Calculate number of elements to ensure multiple sectors are required.
unsigned add_count =
@@ -540,13 +557,13 @@
if (add_idx == add_count - 1) { // last value
memset(buffer.data(), kGoodVal, buffer.size());
}
- ASSERT_OK(kvs.Put(key, buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK, kvs.Put(key, buffer.data(), buffer.size()));
EXPECT_EQ(kvs.KeyCount(), 1);
}
// Verify
memset(buffer.data(), 0, buffer.size());
- ASSERT_OK(kvs.Get(key, buffer.data(), buffer.size()));
+ ASSERT_EQ(Status::OK, kvs.Get(key, buffer.data(), buffer.size()));
for (uint32_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], kGoodVal);
}
@@ -559,7 +576,7 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
ASSERT_EQ(std::strlen(keys[0]), 8U); // Easier for alignment
ASSERT_EQ(std::strlen(keys[2]), 8U); // Easier for alignment
@@ -570,13 +587,13 @@
constexpr uint8_t kKey0Pattern = 0xBA;
memset(buffer.data(), kKey0Pattern, kvs_attr.DataSize());
- ASSERT_OK(kvs.Put(keys[0], buffer.data(), kvs_attr.DataSize()));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], buffer.data(), kvs_attr.DataSize()));
bytes_remaining -= kvs_attr.MinPutSize();
memset(buffer.data(), 1, kvs_attr.DataSize());
- ASSERT_OK(kvs.Put(keys[2], buffer.data(), kvs_attr.DataSize()));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[2], buffer.data(), kvs_attr.DataSize()));
bytes_remaining -= kvs_attr.MinPutSize();
EXPECT_EQ(kvs.KeyCount(), 2);
- ASSERT_OK(kvs.Erase(keys[2]));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[2]));
bytes_remaining -= kvs_attr.EraseSize();
EXPECT_EQ(kvs.KeyCount(), 1);
@@ -586,7 +603,7 @@
// Verify key[0]
memset(buffer.data(), 0, kvs_attr.DataSize());
- ASSERT_OK(kvs.Get(keys[0], buffer.data(), kvs_attr.DataSize()));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], buffer.data(), kvs_attr.DataSize()));
for (uint32_t i = 0; i < kvs_attr.DataSize(); i++) {
EXPECT_EQ(buffer[i], kKey0Pattern);
}
@@ -597,19 +614,19 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
const uint8_t kValue1 = 0xDA;
const uint8_t kValue2 = 0x12;
uint8_t value[1];
- ASSERT_OK(kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
EXPECT_EQ(kvs.KeyCount(), 1);
- ASSERT_OK(kvs.Erase(keys[0]));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
EXPECT_EQ(kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
- ASSERT_OK(kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
- ASSERT_OK(kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
- ASSERT_OK(kvs.Erase(keys[1]));
- EXPECT_OK(kvs.Get(keys[2], value, sizeof(value)));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[1]));
+ EXPECT_EQ(Status::OK, kvs.Get(keys[2], value, sizeof(value)));
EXPECT_EQ(kValue2, value[0]);
EXPECT_EQ(kvs.KeyCount(), 1);
@@ -670,38 +687,48 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Alignment to 16
};
// clang-format on
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// We don't actually care about the size values provided, since we are only
// using kvs_attr to get Sector Size
KvsAttributes kvs_attr(8, 8);
if (test_partition.GetAlignmentBytes() == 1) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
- ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(kvs_attr.SectorHeaderSize(),
kKvsTestDataAligned1Bottom,
sizeof(kKvsTestDataAligned1Bottom)));
} else if (test_partition.GetAlignmentBytes() == 2) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
- ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(kvs_attr.SectorHeaderSize(),
kKvsTestDataAligned2Bottom,
sizeof(kKvsTestDataAligned2Bottom)));
} else if (test_partition.GetAlignmentBytes() == 8) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
- ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(kvs_attr.SectorHeaderSize(),
kKvsTestDataAligned8Bottom,
sizeof(kKvsTestDataAligned8Bottom)));
} else if (test_partition.GetAlignmentBytes() == 16) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
- ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+ ASSERT_EQ(
+ Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(kvs_attr.SectorHeaderSize(),
kKvsTestDataAligned16Bottom,
sizeof(kKvsTestDataAligned16Bottom)));
} else {
- LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
- ASSERT_OK(false);
+ PW_LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
+ ASSERT_EQ(Status::OK, false);
}
EXPECT_EQ(kvs_local_.Enable(), Status::OK);
@@ -711,21 +738,22 @@
// Value with correct CRC should still be available.
uint32_t test2 = 0;
- ASSERT_OK(kvs_local_.Get(
- keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+ ASSERT_EQ(Status::OK,
+ kvs_local_.Get(
+ keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
EXPECT_EQ(kTestPattern, test2);
// Test rewriting over corrupted data.
- ASSERT_OK(kvs_local_.Put(keys[0], kTestPattern));
+ ASSERT_EQ(Status::OK, kvs_local_.Put(keys[0], kTestPattern));
test2 = 0;
- EXPECT_OK(kvs_local_.Get(keys[0], &test2));
+ EXPECT_EQ(Status::OK, kvs_local_.Get(keys[0], &test2));
EXPECT_EQ(kTestPattern, test2);
// Check correct when re-enabled
kvs_local_.Disable();
EXPECT_EQ(kvs_local_.Enable(), Status::OK);
test2 = 0;
- EXPECT_OK(kvs_local_.Get(keys[0], &test2));
+ EXPECT_EQ(Status::OK, kvs_local_.Get(keys[0], &test2));
EXPECT_EQ(kTestPattern, test2);
}
@@ -744,10 +772,11 @@
// Test only runs on 1 byte alignment partitions
test_partition.Erase(0, test_partition.GetSectorCount());
test_partition.Write(0, kKvsTestDataAligned1, sizeof(kKvsTestDataAligned1));
- EXPECT_OK(kvs_local_.Enable());
+ EXPECT_EQ(Status::OK, kvs_local_.Enable());
uint32_t test2 = 0;
- ASSERT_OK(kvs_local_.Get(
- keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+ ASSERT_EQ(Status::OK,
+ kvs_local_.Get(
+ keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
EXPECT_EQ(kTestPattern, test2);
}
}
@@ -757,16 +786,17 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
kvs.Disable();
- EXPECT_OK(kvs_local_.Enable());
+ EXPECT_EQ(Status::OK, kvs_local_.Enable());
// Write value
const uint8_t kValue = 0xDA;
- ASSERT_OK(kvs_local_.Put(keys[0], &kValue, sizeof(kValue)));
+ ASSERT_EQ(Status::OK, kvs_local_.Put(keys[0], &kValue, sizeof(kValue)));
uint8_t value;
- ASSERT_OK(kvs_local_.Get(
- keys[0], reinterpret_cast<uint8_t*>(&value), sizeof(value)));
+ ASSERT_EQ(Status::OK,
+ kvs_local_.Get(
+ keys[0], reinterpret_cast<uint8_t*>(&value), sizeof(value)));
// Verify
EXPECT_EQ(kValue, value);
@@ -777,19 +807,19 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Write value
const uint8_t kValue = 0xDA;
- ASSERT_OK(kvs.Put(keys[0], &kValue, sizeof(kValue)));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], &kValue, sizeof(kValue)));
- ASSERT_OK(kvs.Erase(keys[0]));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
uint8_t value[1];
ASSERT_EQ(kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
// Reset KVS, ensure captured at enable
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
ASSERT_EQ(kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
}
@@ -798,14 +828,14 @@
test_partition.Erase(0, test_partition.GetSectorCount());
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Store a value with the convenience method.
const uint32_t kValue = 0x12345678;
- ASSERT_OK(kvs.Put(keys[0], kValue));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], kValue));
// Read it back with the other convenience method.
uint32_t value;
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(kValue, value);
// Make sure we cannot get something where size isn't what we expect
@@ -854,53 +884,64 @@
};
// clang-format on
- ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+ ASSERT_EQ(Status::OK,
+ test_partition.Erase(0, test_partition.GetSectorCount()));
// We don't actually care about the size values provided, since we are only
// using kvs_attr to get Sector Size
KvsAttributes kvs_attr(8, 8);
- pw::FlashPartition::Address address = kvs_attr.SectorHeaderSize();
+ FlashPartition::Address address = kvs_attr.SectorHeaderSize();
if (test_partition.GetAlignmentBytes() == 1) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
- ASSERT_OK(test_partition.Write(address,
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(address,
kKvsTestDataAligned1Bottom,
sizeof(kKvsTestDataAligned1Bottom)));
address += sizeof(kKvsTestDataAligned1Bottom);
} else if (test_partition.GetAlignmentBytes() == 2) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
- ASSERT_OK(test_partition.Write(address,
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(address,
kKvsTestDataAligned2Bottom,
sizeof(kKvsTestDataAligned2Bottom)));
address += sizeof(kKvsTestDataAligned2Bottom);
} else if (test_partition.GetAlignmentBytes() == 8) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
- ASSERT_OK(test_partition.Write(address,
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(address,
kKvsTestDataAligned8Bottom,
sizeof(kKvsTestDataAligned8Bottom)));
address += sizeof(kKvsTestDataAligned8Bottom);
} else if (test_partition.GetAlignmentBytes() == 16) {
- ASSERT_OK(test_partition.Write(
- 0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
- ASSERT_OK(test_partition.Write(address,
+ ASSERT_EQ(
+ Status::OK,
+ test_partition.Write(
+ 0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
+ ASSERT_EQ(Status::OK,
+ test_partition.Write(address,
kKvsTestDataAligned16Bottom,
sizeof(kKvsTestDataAligned16Bottom)));
address += sizeof(kKvsTestDataAligned16Bottom);
} else {
- LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
+ PW_LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
ASSERT_EQ(true, false);
}
- ASSERT_OK(kvs_local_.Enable());
+ ASSERT_EQ(Status::OK, kvs_local_.Enable());
EXPECT_TRUE(kvs_local_.IsEnabled());
// Put in same key/value pair
- ASSERT_OK(kvs_local_.Put(keys[1], kTestPattern));
+ ASSERT_EQ(Status::OK, kvs_local_.Put(keys[1], kTestPattern));
bool is_erased = false;
- ASSERT_OK(test_partition.IsChunkErased(
- address, test_partition.GetAlignmentBytes(), &is_erased));
+ ASSERT_EQ(Status::OK,
+ test_partition.IsChunkErased(
+ address, test_partition.GetAlignmentBytes(), &is_erased));
EXPECT_EQ(is_erased, true);
}
@@ -909,14 +950,14 @@
// the sector.
TEST_F(KeyValueStoreTest, FillSector2) {
if (test_partition.GetSectorCount() < 3) {
- LOG_INFO("Not enough sectors, skipping test.");
+ PW_LOG_INFO("Not enough sectors, skipping test.");
return; // need at least 3 sectors
}
// Reset KVS
kvs.Disable();
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Start of by filling flash sector to near full
constexpr int kHalfBufferSize = buffer.size() / 2;
@@ -931,11 +972,12 @@
size_t new_keyvalue_size = 0;
size_t alignment = test_partition.GetAlignmentBytes();
// Starts on second sector since it will try to keep first sector free
- pw::FlashPartition::Address read_address =
+ FlashPartition::Address read_address =
2 * test_partition.GetSectorSizeBytes() - alignment;
for (; read_address > 0; read_address -= alignment) {
bool is_erased = false;
- ASSERT_OK(
+ ASSERT_EQ(
+ Status::OK,
test_partition.IsChunkErased(read_address, alignment, &is_erased));
if (is_erased) {
new_keyvalue_size += alignment;
@@ -953,15 +995,15 @@
constexpr uint8_t kTestPattern = 0xBA;
new_keyvalue_size -= kValueLessThanChunkHeaderSize;
memset(buffer.data(), kTestPattern, new_keyvalue_size);
- ASSERT_OK(kvs.Put(kNewKey, buffer.data(), new_keyvalue_size));
+ ASSERT_EQ(Status::OK, kvs.Put(kNewKey, buffer.data(), new_keyvalue_size));
// In failed corner case, adding new key is deceptively successful. It isn't
// until KVS is disabled and reenabled that issue can be detected.
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Might as well check that new key-value is what we expect it to be
- ASSERT_OK(kvs.Get(kNewKey, buffer.data(), new_keyvalue_size));
+ ASSERT_EQ(Status::OK, kvs.Get(kNewKey, buffer.data(), new_keyvalue_size));
for (size_t i = 0; i < new_keyvalue_size; i++) {
EXPECT_EQ(buffer[i], kTestPattern);
}
@@ -980,7 +1022,7 @@
// Reset KVS
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Try some case that are expected to fail
ASSERT_EQ(kvs.GetValueSize(keys[0], &value_size), Status::NOT_FOUND);
@@ -989,12 +1031,12 @@
// Add key[0] and test we get the right value size for it.
memset(buffer.data(), kKey0Pattern, kSizeOfValueToFill);
- ASSERT_OK(kvs.Put(keys[0], buffer.data(), kSizeOfValueToFill));
- ASSERT_OK(kvs.GetValueSize(keys[0], &value_size));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], buffer.data(), kSizeOfValueToFill));
+ ASSERT_EQ(Status::OK, kvs.GetValueSize(keys[0], &value_size));
ASSERT_EQ(value_size, kSizeOfValueToFill);
// Verify after erase key is not found
- ASSERT_OK(kvs.Erase(keys[0]));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
ASSERT_EQ(kvs.GetValueSize(keys[0], &value_size), Status::NOT_FOUND);
}
@@ -1002,7 +1044,7 @@
// Reset KVS
kvs.Disable();
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
// Get exactly the number of bytes that can fit in the space remaining for
// a large value, accounting for alignment.
@@ -1035,15 +1077,15 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
- ASSERT_OK(kvs.Put(kKey, kValue1));
+ ASSERT_EQ(Status::OK, kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Put(kKey, kValue1));
// Now try to rewrite with the similar value.
- ASSERT_OK(kvs.Put(kKey, kValue2));
+ ASSERT_EQ(Status::OK, kvs.Put(kKey, kValue2));
// Read it back and check it is correct
char value[3];
- ASSERT_OK(kvs.Get(kKey, value, sizeof(value)));
+ ASSERT_EQ(Status::OK, kvs.Get(kKey, value, sizeof(value)));
ASSERT_EQ(memcmp(value, kValue2, sizeof(value)), 0);
}
@@ -1052,11 +1094,11 @@
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
const uint8_t kValue = 0xDA;
- ASSERT_OK(kvs.Put(keys[0], &kValue, sizeof(kValue)));
- ASSERT_OK(kvs.Erase(keys[0]));
+ ASSERT_EQ(Status::OK, kvs.Put(keys[0], &kValue, sizeof(kValue)));
+ ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
uint16_t crc = CalcTestPartitionCrc();
EXPECT_EQ(kvs.Erase(keys[0]), Status::NOT_FOUND);
// Verify the flash has not changed
@@ -1073,18 +1115,18 @@
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs1.Enable());
- ASSERT_OK(kvs2.Enable());
+ ASSERT_EQ(Status::OK, kvs1.Enable());
+ ASSERT_EQ(Status::OK, kvs2.Enable());
int values1[3] = {100, 101, 102};
- ASSERT_OK(kvs1.Put(keys[0], values1[0]));
- ASSERT_OK(kvs1.Put(keys[1], values1[1]));
- ASSERT_OK(kvs1.Put(keys[2], values1[2]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
int values2[3] = {200, 201, 202};
- ASSERT_OK(kvs2.Put(keys[0], values2[0]));
- ASSERT_OK(kvs2.Put(keys[1], values2[1]));
- ASSERT_OK(kvs2.Erase(keys[1]));
+ ASSERT_EQ(Status::OK, kvs2.Put(keys[0], values2[0]));
+ ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values2[1]));
+ ASSERT_EQ(Status::OK, kvs2.Erase(keys[1]));
kvs1.Disable();
kvs2.Disable();
@@ -1094,19 +1136,20 @@
// key 2 is only in first sector
uint64_t mark_clean_count = 5;
- ASSERT_OK(PaddedWrite(&test_partition_sector1,
+ ASSERT_EQ(Status::OK,
+ PaddedWrite(&test_partition_sector1,
RoundUpForAlignment(KeyValueStore::kHeaderSize),
reinterpret_cast<uint8_t*>(&mark_clean_count),
sizeof(uint64_t)));
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
int value;
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(values2[0], value);
ASSERT_EQ(kvs.Get(keys[1], &value), Status::NOT_FOUND);
- ASSERT_OK(kvs.Get(keys[2], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
ASSERT_EQ(values1[2], value);
if (test_partition.GetSectorCount() == 2) {
@@ -1118,25 +1161,29 @@
}
mark_clean_count--;
- ASSERT_OK(PaddedWrite(&test_partition_sector2,
+ ASSERT_EQ(Status::OK,
+ PaddedWrite(&test_partition_sector2,
RoundUpForAlignment(KeyValueStore::kHeaderSize),
reinterpret_cast<uint8_t*>(&mark_clean_count),
sizeof(uint64_t)));
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
EXPECT_EQ(kvs.PendingCleanCount(), 2u);
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(values1[0], value);
- ASSERT_OK(kvs.Get(keys[1], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
ASSERT_EQ(values1[1], value);
- ASSERT_OK(kvs.Get(keys[2], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
ASSERT_EQ(values1[2], value);
}
+// TODO: temporary
+size_t CurrentTaskStackFree() { return -1; }
+
TEST_F(KeyValueStoreTest, PartialClean) {
if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 2) {
- LOG_ERROR("Not enough stack for test, skipping");
+ PW_LOG_ERROR("Not enough stack for test, skipping");
return;
}
StackHeavyPartialClean();
@@ -1149,40 +1196,42 @@
KeyValueStore kvs1(&test_partition_sector1);
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs1.Enable());
+ ASSERT_EQ(Status::OK, kvs1.Enable());
int values1[3] = {100, 101, 102};
- ASSERT_OK(kvs1.Put(keys[0], values1[0]));
- ASSERT_OK(kvs1.Put(keys[1], values1[1]));
- ASSERT_OK(kvs1.Put(keys[2], values1[2] - 100)); // force a rewrite
- ASSERT_OK(kvs1.Put(keys[2], values1[2]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
+ ASSERT_EQ(Status::OK,
+ kvs1.Put(keys[2], values1[2] - 100)); // force a rewrite
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
kvs1.Disable();
uint64_t mark_clean_count = 5;
- ASSERT_OK(PaddedWrite(&test_partition_sector1,
+ ASSERT_EQ(Status::OK,
+ PaddedWrite(&test_partition_sector1,
RoundUpForAlignment(KeyValueStore::kHeaderSize),
reinterpret_cast<uint8_t*>(&mark_clean_count),
sizeof(uint64_t)));
// Reset KVS
kvs.Disable();
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
int value;
EXPECT_EQ(kvs.PendingCleanCount(), 1u);
- ASSERT_OK(kvs.CleanAll());
+ ASSERT_EQ(Status::OK, kvs.CleanAll());
EXPECT_EQ(kvs.PendingCleanCount(), 0u);
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(values1[0], value);
- ASSERT_OK(kvs.Get(keys[1], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
ASSERT_EQ(values1[1], value);
- ASSERT_OK(kvs.Get(keys[2], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
ASSERT_EQ(values1[2], value);
}
TEST_F(KeyValueStoreTest, CleanAll) {
if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 1) {
- LOG_ERROR("Not enough stack for test, skipping");
+ PW_LOG_ERROR("Not enough stack for test, skipping");
return;
}
StackHeavyCleanAll();
@@ -1198,18 +1247,18 @@
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs1.Enable());
- ASSERT_OK(kvs2.Enable());
+ ASSERT_EQ(Status::OK, kvs1.Enable());
+ ASSERT_EQ(Status::OK, kvs2.Enable());
int values1[3] = {100, 101, 102};
- ASSERT_OK(kvs1.Put(keys[0], values1[0]));
- ASSERT_OK(kvs1.Put(keys[1], values1[1]));
- ASSERT_OK(kvs1.Put(keys[2], values1[2]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
int values2[3] = {200, 201, 202};
- ASSERT_OK(kvs2.Put(keys[0], values2[0]));
- ASSERT_OK(kvs2.Put(keys[1], values2[1]));
- ASSERT_OK(kvs2.Erase(keys[1]));
+ ASSERT_EQ(Status::OK, kvs2.Put(keys[0], values2[0]));
+ ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values2[1]));
+ ASSERT_EQ(Status::OK, kvs2.Erase(keys[1]));
kvs1.Disable();
kvs2.Disable();
@@ -1220,18 +1269,19 @@
// key 2 is only in first sector
uint64_t mark_clean_count = 4569877515;
- ASSERT_OK(PaddedWrite(&test_partition_sector1,
+ ASSERT_EQ(Status::OK,
+ PaddedWrite(&test_partition_sector1,
RoundUpForAlignment(KeyValueStore::kHeaderSize),
reinterpret_cast<uint8_t*>(&mark_clean_count),
sizeof(uint64_t)));
// Reset KVS
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
int value;
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(values2[0], value);
ASSERT_EQ(kvs.Get(keys[1], &value), Status::NOT_FOUND);
- ASSERT_OK(kvs.Get(keys[2], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
ASSERT_EQ(values1[2], value);
if (test_partition.GetSectorCount() == 2) {
@@ -1245,24 +1295,25 @@
kvs.Disable();
mark_clean_count--;
- ASSERT_OK(PaddedWrite(&test_partition_sector2,
+ ASSERT_EQ(Status::OK,
+ PaddedWrite(&test_partition_sector2,
RoundUpForAlignment(KeyValueStore::kHeaderSize),
reinterpret_cast<uint8_t*>(&mark_clean_count),
sizeof(uint64_t)));
// Reset KVS
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
EXPECT_EQ(kvs.PendingCleanCount(), 2u);
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(values1[0], value);
- ASSERT_OK(kvs.Get(keys[1], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
ASSERT_EQ(values1[1], value);
- ASSERT_OK(kvs.Get(keys[2], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
ASSERT_EQ(values1[2], value);
}
TEST_F(KeyValueStoreTest, PartialCleanLargeCounts) {
if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 2) {
- LOG_ERROR("Not enough stack for test, skipping");
+ PW_LOG_ERROR("Not enough stack for test, skipping");
return;
}
StackHeavyPartialCleanLargeCounts();
@@ -1280,31 +1331,31 @@
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs1.Enable());
- ASSERT_OK(kvs2.Enable());
+ ASSERT_EQ(Status::OK, kvs1.Enable());
+ ASSERT_EQ(Status::OK, kvs2.Enable());
int values[3] = {100, 101};
- ASSERT_OK(kvs1.Put(keys[0], values[0]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values[0]));
ASSERT_FALSE(kvs1.HasEmptySector());
- ASSERT_OK(kvs2.Put(keys[1], values[1]));
+ ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values[1]));
ASSERT_FALSE(kvs2.HasEmptySector());
kvs1.Disable();
kvs2.Disable();
// Reset KVS
- ASSERT_OK(kvs_both.Enable());
+ ASSERT_EQ(Status::OK, kvs_both.Enable());
ASSERT_TRUE(kvs_both.HasEmptySector());
int value;
- ASSERT_OK(kvs_both.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs_both.Get(keys[0], &value));
ASSERT_EQ(values[0], value);
- ASSERT_OK(kvs_both.Get(keys[1], &value));
+ ASSERT_EQ(Status::OK, kvs_both.Get(keys[1], &value));
ASSERT_EQ(values[1], value);
}
TEST_F(KeyValueStoreTest, RecoverNoFreeSectors) {
if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 3) {
- LOG_ERROR("Not enough stack for test, skipping");
+ PW_LOG_ERROR("Not enough stack for test, skipping");
return;
}
StackHeavyRecoverNoFreeSectors();
@@ -1319,45 +1370,46 @@
test_partition.Erase(0, test_partition.GetSectorCount());
- ASSERT_OK(kvs1.Enable());
+ ASSERT_EQ(Status::OK, kvs1.Enable());
int values[3] = {100, 101, 102};
- ASSERT_OK(kvs1.Put(keys[0], values[0]));
- ASSERT_OK(kvs1.Put(keys[1], values[1]));
- ASSERT_OK(kvs1.Put(keys[2], values[2]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values[0]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values[1]));
+ ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values[2]));
kvs1.Disable();
kvs.Disable();
uint64_t mark_clean_count = 1;
- ASSERT_OK(PaddedWrite(&test_partition_sector1,
+ ASSERT_EQ(Status::OK,
+ PaddedWrite(&test_partition_sector1,
RoundUpForAlignment(KeyValueStore::kHeaderSize),
reinterpret_cast<uint8_t*>(&mark_clean_count),
sizeof(uint64_t)));
// Reset KVS
- ASSERT_OK(kvs.Enable());
+ ASSERT_EQ(Status::OK, kvs.Enable());
EXPECT_EQ(kvs.PendingCleanCount(), 1u);
bool all_sectors_have_been_cleaned = false;
- ASSERT_OK(kvs.CleanOneSector(&all_sectors_have_been_cleaned));
+ ASSERT_EQ(Status::OK, kvs.CleanOneSector(&all_sectors_have_been_cleaned));
EXPECT_EQ(all_sectors_have_been_cleaned, true);
EXPECT_EQ(kvs.PendingCleanCount(), 0u);
- ASSERT_OK(kvs.CleanOneSector(&all_sectors_have_been_cleaned));
+ ASSERT_EQ(Status::OK, kvs.CleanOneSector(&all_sectors_have_been_cleaned));
EXPECT_EQ(all_sectors_have_been_cleaned, true);
int value;
- ASSERT_OK(kvs.Get(keys[0], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
ASSERT_EQ(values[0], value);
- ASSERT_OK(kvs.Get(keys[1], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
ASSERT_EQ(values[1], value);
- ASSERT_OK(kvs.Get(keys[2], &value));
+ ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
ASSERT_EQ(values[2], value);
}
TEST_F(KeyValueStoreTest, CleanOneSector) {
if (CurrentTaskStackFree() < sizeof(KeyValueStore)) {
- LOG_ERROR("Not enough stack for test, skipping");
+ PW_LOG_ERROR("Not enough stack for test, skipping");
return;
}
StackHeavyCleanOneSector();
@@ -1367,30 +1419,30 @@
TEST_F(KeyValueStoreTest, LargePartition) {
if (CurrentTaskStackFree() < sizeof(KeyValueStore)) {
- LOG_ERROR("Not enough stack for test, skipping");
+ PW_LOG_ERROR("Not enough stack for test, skipping");
return;
}
large_test_partition.Erase(0, large_test_partition.GetSectorCount());
KeyValueStore large_kvs(&large_test_partition);
// Reset KVS
large_kvs.Disable();
- ASSERT_OK(large_kvs.Enable());
+ ASSERT_EQ(Status::OK, large_kvs.Enable());
const uint8_t kValue1 = 0xDA;
const uint8_t kValue2 = 0x12;
uint8_t value[1];
- ASSERT_OK(large_kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
+ ASSERT_EQ(Status::OK, large_kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
EXPECT_EQ(large_kvs.KeyCount(), 1);
- ASSERT_OK(large_kvs.Erase(keys[0]));
+ ASSERT_EQ(Status::OK, large_kvs.Erase(keys[0]));
EXPECT_EQ(large_kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
- ASSERT_OK(large_kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
- ASSERT_OK(large_kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
- ASSERT_OK(large_kvs.Erase(keys[1]));
- EXPECT_OK(large_kvs.Get(keys[2], value, sizeof(value)));
+ ASSERT_EQ(Status::OK, large_kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
+ ASSERT_EQ(Status::OK, large_kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
+ ASSERT_EQ(Status::OK, large_kvs.Erase(keys[1]));
+ EXPECT_EQ(Status::OK, large_kvs.Get(keys[2], value, sizeof(value)));
EXPECT_EQ(kValue2, value[0]);
ASSERT_EQ(large_kvs.Get(keys[1], &value), Status::NOT_FOUND);
EXPECT_EQ(large_kvs.KeyCount(), 1);
}
#endif // USE_MEMORY_BUFFER
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/assert.h b/pw_kvs/public/pw_kvs/assert.h
new file mode 100644
index 0000000..36f232b
--- /dev/null
+++ b/pw_kvs/public/pw_kvs/assert.h
@@ -0,0 +1,69 @@
+// Copyright 2020 The Pigweed 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.
+#pragma once
+
+#include <algorithm>
+#include <type_traits>
+
+// Compares the provided value to nullptr and returns it. This is intended to be
+// used as part of another statement.
+#define CHECK_NOTNULL(value) \
+ ::pw::log::CheckNotNull("", __LINE__, #value " != nullptr", value)
+
+// In release builds, DCHECK_NOTNULL simply passes along the value.
+// DCHECK_NOTNULL must not be used as a standalone expression, since the result
+// would be unused on release builds. Use DCHECK_NE instead.
+//#define DCHECK_NOTNULL(value) value
+
+#define DCHECK_NOTNULL(value) \
+ ::pw::log::DCheckNotNull("", __LINE__, #value " != nullptr", value)
+
+namespace pw::log {
+
+template <typename T>
+constexpr T CheckNotNull(const char* /* file */,
+ unsigned /* line */,
+ const char* /* message */,
+ T&& value) {
+ static_assert(!std::is_null_pointer<T>(),
+ "CHECK_NOTNULL statements cannot be passed nullptr");
+ if (value == nullptr) {
+ std::exit(1);
+ }
+ return std::forward<T>(value);
+}
+
+// DCHECK_NOTNULL cannot be used in standalone expressions, so add a
+// [[nodiscard]] attribute to prevent this in debug builds. Standalone
+// DCHECK_NOTNULL statements in release builds trigger an unused-value warning.
+template <typename T>
+[[nodiscard]] constexpr T DCheckNotNull(const char* file,
+ unsigned line,
+ const char* message,
+ T&& value) {
+ return CheckNotNull<T>(file, line, message, std::forward<T>(value));
+}
+
+} // namespace pw::log
+
+// Assert stubs
+#define DCHECK CHECK
+#define DCHECK_EQ CHECK_EQ
+
+#define CHECK(...)
+#define CHECK_EQ(...)
+#define CHECK_GE(...)
+#define CHECK_GT(...)
+#define CHECK_LE(...)
+#define CHECK_LT(...)
diff --git a/pw_kvs/public/pw_kvs/flash.h b/pw_kvs/public/pw_kvs/flash.h
index 5cb80cd..6eecea7 100644
--- a/pw_kvs/public/pw_kvs/flash.h
+++ b/pw_kvs/public/pw_kvs/flash.h
@@ -13,9 +13,9 @@
// the License.
#pragma once
-#include "pw_kvs/devices/flash_memory.h"
+#include "pw_kvs/flash_memory.h"
-namespace pw {
+namespace pw::kvs {
// Writes a buffer which is not guaranteed to be aligned, pads remaining
// bytes with 0.
@@ -30,4 +30,4 @@
FlashPartition::Address address,
uint16_t size);
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/flash_memory.h b/pw_kvs/public/pw_kvs/flash_memory.h
index 707f128..d62f794 100644
--- a/pw_kvs/public/pw_kvs/flash_memory.h
+++ b/pw_kvs/public/pw_kvs/flash_memory.h
@@ -14,14 +14,16 @@
#pragma once
#include <algorithm>
+#include <cinttypes>
+#include <cstring>
#include "pw_kvs/assert.h"
-#include "pw_kvs/logging.h"
-#include "pw_kvs/peripherals/partition_table_entry.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/status_macros.h"
+#include "pw_kvs/partition_table_entry.h"
+#include "pw_log/log.h"
+#include "pw_status/status.h"
-namespace pw {
+namespace pw::kvs {
+
class FlashMemory {
public:
// The flash address is in the range of: 0 to FlashSize.
@@ -39,6 +41,8 @@
sector_start_(sector_start),
erased_memory_content_(erased_memory_content) {}
+ virtual ~FlashMemory() = default;
+
virtual Status Enable() = 0;
virtual Status Disable() = 0;
virtual bool IsEnabled() const = 0;
@@ -72,9 +76,7 @@
// Convert an Address to an MCU pointer, this can be used for memory
// mapped reads. Return NULL if the memory is not memory mapped.
- virtual uint8_t* FlashAddressToMcuAddress(Address address) const {
- return nullptr;
- }
+ virtual uint8_t* FlashAddressToMcuAddress(Address) const { return nullptr; }
// GetStartSector() is useful for FlashMemory instances where the
// sector start is not 0. (ex.: cases where there are portions of flash
@@ -137,9 +139,7 @@
bool IsEnabled() const override { return flash_.IsEnabled(); }
Status SelfTest() override { return flash_.SelfTest(); }
- Status Erase(Address flash_address, uint32_t num_sectors) override {
- return Status::UNIMPLEMENTED;
- }
+ Status Erase(Address, uint32_t) override { return Status::UNIMPLEMENTED; }
Status Read(uint8_t* destination_ram_address,
Address source_flash_address,
@@ -185,6 +185,8 @@
entry.partition_start_sector_index + 1),
permission_(entry.partition_permission) {}
+ virtual ~FlashPartition() = default;
+
// Erase num_sectors starting at a given address. Blocking call.
// Address should be on a sector boundary.
// Returns: OK, on success.
@@ -193,9 +195,14 @@
// PERMISSION_DENIED, if partition is read only.
// UNKNOWN, on HAL error
virtual Status Erase(Address address, uint32_t num_sectors) {
- RETURN_STATUS_IF(permission_ == PartitionPermission::kReadOnly,
- Status::PERMISSION_DENIED);
- RETURN_IF_ERROR(CheckBounds(address, num_sectors * GetSectorSizeBytes()));
+ if (permission_ == PartitionPermission::kReadOnly) {
+ return Status::PERMISSION_DENIED;
+ }
+ if (Status status =
+ CheckBounds(address, num_sectors * GetSectorSizeBytes());
+ !status.ok()) {
+ return status;
+ }
return flash_.Erase(PartitionToFlashAddress(address), num_sectors);
}
@@ -207,7 +214,9 @@
virtual Status Read(uint8_t* destination_ram_address,
Address source_flash_address,
uint32_t len) {
- RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+ if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+ return status;
+ }
return flash_.Read(destination_ram_address,
PartitionToFlashAddress(source_flash_address),
len);
@@ -222,9 +231,13 @@
virtual Status Write(Address destination_flash_address,
const uint8_t* source_ram_address,
uint32_t len) {
- RETURN_STATUS_IF(permission_ == PartitionPermission::kReadOnly,
- Status::PERMISSION_DENIED);
- RETURN_IF_ERROR(CheckBounds(destination_flash_address, len));
+ if (permission_ == PartitionPermission::kReadOnly) {
+ return Status::PERMISSION_DENIED;
+ }
+ if (Status status = CheckBounds(destination_flash_address, len);
+ !status.ok()) {
+ return status;
+ }
return flash_.Write(PartitionToFlashAddress(destination_flash_address),
source_ram_address,
len);
@@ -243,24 +256,31 @@
// function. Using 16 because it's the alignment of encrypted flash.
const uint8_t kMaxAlignment = 16;
// Relying on Read() to check address and len arguments.
- RETURN_STATUS_IF(!is_erased, Status::INVALID_ARGUMENT);
+ if (!is_erased) {
+ return Status::INVALID_ARGUMENT;
+ }
uint8_t alignment = GetAlignmentBytes();
- RETURN_STATUS_IF(alignment > kMaxAlignment, Status::INVALID_ARGUMENT);
- RETURN_STATUS_IF(kMaxAlignment % alignment, Status::INVALID_ARGUMENT);
- RETURN_STATUS_IF(len % alignment, Status::INVALID_ARGUMENT);
+ if (alignment > kMaxAlignment || kMaxAlignment % alignment ||
+ len % alignment) {
+ return Status::INVALID_ARGUMENT;
+ }
uint8_t buffer[kMaxAlignment];
uint8_t erased_pattern_buffer[kMaxAlignment];
size_t offset = 0;
- memset(erased_pattern_buffer,
- flash_.GetErasedMemoryContent(),
- sizeof(erased_pattern_buffer));
+ std::memset(erased_pattern_buffer,
+ flash_.GetErasedMemoryContent(),
+ sizeof(erased_pattern_buffer));
*is_erased = false;
while (len > 0) {
// Check earlier that len is aligned, no need to round up
uint16_t read_size = std::min(static_cast<uint32_t>(sizeof(buffer)), len);
- RETURN_IF_ERROR(Read(buffer, source_flash_address + offset, read_size));
- if (memcmp(buffer, erased_pattern_buffer, read_size)) {
+ if (Status status =
+ Read(buffer, source_flash_address + offset, read_size);
+ !status.ok()) {
+ return status;
+ }
+ if (std::memcmp(buffer, erased_pattern_buffer, read_size)) {
// Detected memory chunk is not entirely erased
return Status::OK;
}
@@ -301,8 +321,11 @@
protected:
Status CheckBounds(Address address, uint32_t len) const {
if (address + len > GetSizeBytes()) {
- LOG(ERROR) << "Attempted out-of-bound flash memory access (address:"
- << address << " length:" << len << ")";
+ PW_LOG_ERROR(
+ "Attempted out-of-bound flash memory access (address: %" PRIu32
+ " length: %zu)",
+ address,
+ len);
return Status::INVALID_ARGUMENT;
}
return Status::OK;
@@ -331,14 +354,20 @@
sector_count_(sector_count) {}
Status Erase(Address address, uint32_t num_sectors) override {
- RETURN_IF_ERROR(CheckBounds(address, num_sectors * GetSectorSizeBytes()));
+ if (Status status =
+ CheckBounds(address, num_sectors * GetSectorSizeBytes());
+ !status.ok()) {
+ return status;
+ }
return partition_->Erase(ParentAddress(address), num_sectors);
}
Status Read(uint8_t* destination_ram_address,
Address source_flash_address,
uint32_t len) override {
- RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+ if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+ return status;
+ }
return partition_->Read(
destination_ram_address, ParentAddress(source_flash_address), len);
}
@@ -346,7 +375,10 @@
Status Write(Address destination_flash_address,
const uint8_t* source_ram_address,
uint32_t len) override {
- RETURN_IF_ERROR(CheckBounds(destination_flash_address, len));
+ if (Status status = CheckBounds(destination_flash_address, len);
+ !status.ok()) {
+ return status;
+ }
return partition_->Write(
ParentAddress(destination_flash_address), source_ram_address, len);
}
@@ -354,7 +386,9 @@
Status IsChunkErased(Address source_flash_address,
uint32_t len,
bool* is_erased) override {
- RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+ if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+ return status;
+ }
return partition_->IsChunkErased(
ParentAddress(source_flash_address), len, is_erased);
}
@@ -374,4 +408,4 @@
const uint32_t sector_count_;
};
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/in_memory_fake_flash.h b/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
index a67c770..d2ea67c 100644
--- a/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
+++ b/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
@@ -15,11 +15,10 @@
#include <array>
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/status_macros.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
-namespace pw {
+namespace pw::kvs {
// This creates a buffer which mimics the behaviour of flash (requires erase,
// before write, checks alignments, and is addressed in sectors).
@@ -40,12 +39,15 @@
// INVALID_ARGUMENT, if address or sector count is invalid.
// UNKNOWN, on HAL error
Status Erase(Address addr, uint32_t num_sectors) override {
- RETURN_STATUS_IF(addr % GetSectorSizeBytes() != 0,
- Status::INVALID_ARGUMENT);
- RETURN_STATUS_IF(
- addr / GetSectorSizeBytes() + num_sectors > GetSectorCount(),
- Status::UNKNOWN);
- RETURN_STATUS_IF(addr % GetAlignmentBytes() != 0, Status::INVALID_ARGUMENT);
+ if (addr % GetSectorSizeBytes() != 0) {
+ return Status::INVALID_ARGUMENT;
+ }
+ if (addr / GetSectorSizeBytes() + num_sectors > GetSectorCount()) {
+ return Status::UNKNOWN;
+ }
+ if (addr % GetAlignmentBytes() != 0) {
+ return Status::INVALID_ARGUMENT;
+ }
memset(&buffer_[addr], 0xFF, GetSectorSizeBytes() * num_sectors);
return Status::OK;
}
@@ -57,9 +59,9 @@
Status Read(uint8_t* dest_ram_addr,
Address source_flash_addr,
uint32_t len) override {
- RETURN_STATUS_IF(
- (source_flash_addr + len) >= GetSectorCount() * GetSizeBytes(),
- Status::INVALID_ARGUMENT);
+ if ((source_flash_addr + len) >= GetSectorCount() * GetSizeBytes()) {
+ return Status::INVALID_ARGUMENT;
+ }
memcpy(dest_ram_addr, &buffer_[source_flash_addr], len);
return Status::OK;
}
@@ -71,15 +73,16 @@
Status Write(Address dest_flash_addr,
const uint8_t* source_ram_addr,
uint32_t len) override {
- RETURN_STATUS_IF(
- (dest_flash_addr + len) >= GetSectorCount() * GetSizeBytes(),
- Status::INVALID_ARGUMENT);
- RETURN_STATUS_IF(dest_flash_addr % GetAlignmentBytes() != 0,
- Status::INVALID_ARGUMENT);
- RETURN_STATUS_IF(len % GetAlignmentBytes() != 0, Status::INVALID_ARGUMENT);
+ if ((dest_flash_addr + len) >= GetSectorCount() * GetSizeBytes() ||
+ dest_flash_addr % GetAlignmentBytes() != 0 ||
+ len % GetAlignmentBytes() != 0) {
+ return Status::INVALID_ARGUMENT;
+ }
// Check in erased state
for (unsigned i = 0; i < len; i++) {
- RETURN_STATUS_IF(buffer_[dest_flash_addr + i] != 0xFF, Status::UNKNOWN);
+ if (buffer_[dest_flash_addr + i] != 0xFF) {
+ return Status::UNKNOWN;
+ }
}
memcpy(&buffer_[dest_flash_addr], source_ram_addr, len);
return Status::OK;
@@ -89,4 +92,4 @@
std::array<uint8_t, kSectorCount * kSectorSize> buffer_;
};
-} // namespace pw
+} // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index dca6507..d9bb34f 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -16,17 +16,37 @@
#include <algorithm>
#include <type_traits>
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/logging.h"
-#include "pw_kvs/os/mutex.h"
-#include "pw_kvs/status.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
-namespace pw {
+namespace cfg {
+
+// KVS requires a temporary buffer for some operations, this config allows
+// tuning the buffer size. This is a trade-off between a value which is large
+// and therefore requires more RAM, or having a value which is small which will
+// result in some operations taking longer, as the operations are broken into
+// smaller chunks.
+// NOTE: This value can not be smaller then the flash alignment, and it will
+// round the size down to be a multiple of the flash alignment for all
+// operations.
+inline constexpr size_t kKvsBufferSize = 64;
+
+// This represents the maximum amount of keys which can be in the KVS at any
+// given time.
+inline constexpr uint8_t kKvsMaxKeyCount = 50;
+
+// This is the maximum amount of sectors the KVS can operate on, an invalid
+// value will cause an error during enable.
+inline constexpr uint32_t kKvsMaxSectorCount = 20;
+
+} // namespace cfg
+
+namespace pw::kvs {
// This object is very large and should not be placed on the stack.
class KeyValueStore {
public:
- KeyValueStore(FlashPartition* partition) : partition_(*partition) {}
+ constexpr KeyValueStore(FlashPartition* partition) : partition_(*partition) {}
// Enable the KVS, scans the sectors of the partition for any current KVS
// data. Erases and initializes any sectors which are not initialized.
@@ -39,7 +59,7 @@
if (enabled_ == false) {
return;
}
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
enabled_ = false;
}
@@ -67,9 +87,14 @@
Status Get(const char* key, T* value) {
static_assert(std::is_trivially_copyable<T>(), "KVS values must copyable");
static_assert(!std::is_pointer<T>(), "KVS values cannot be pointers");
+
uint16_t value_size = 0;
- RETURN_IF_ERROR(GetValueSize(key, &value_size));
- RETURN_STATUS_IF(value_size != sizeof(T), Status::INVALID_ARGUMENT);
+ if (Status status = GetValueSize(key, &value_size)) {
+ return status;
+ }
+ if (value_size != sizeof(T)) {
+ return Status::INVALID_ARGUMENT;
+ }
return Get(key, value, sizeof(T));
}
@@ -107,11 +132,11 @@
// CleanAll cleans each sector which is currently marked for cleaning.
// Note: if any data is invalid/corrupt it could be lost.
Status CleanAll() {
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
return CleanAllInternal();
}
size_t PendingCleanCount() {
- os::MutexLock lock(&lock_);
+ // TODO: LOCK MUTEX
size_t ret = 0;
for (size_t i = 0; i < SectorCount(); i++) {
ret += sector_space_remaining_[i] == 0 ? 1 : 0;
@@ -345,7 +370,7 @@
}
FlashPartition& partition_;
- os::Mutex lock_;
+ // TODO: MUTEX
bool enabled_ = false;
uint8_t alignment_bytes_ = 0;
uint64_t next_sector_clean_order_ = 0;
@@ -353,7 +378,7 @@
// Free space available in each sector, set to 0 when clean is pending/active
uint32_t sector_space_remaining_[kSectorCountMax] = {0};
uint64_t sector_clean_order_[kSectorCountMax] = {kSectorCleanNotPending};
- KeyMap key_map_[kListCapacityMax] = {{{0}}};
+ KeyMap key_map_[kListCapacityMax] = {};
KeyIndex map_size_ = 0;
// +1 for nul-terminator since keys are stored as Length + Value and no nul
@@ -363,4 +388,4 @@
uint8_t temp_buffer_[cfg::kKvsBufferSize] = {0};
};
-} // namespace pw
+} // namespace pw::kvs