Skip to content

Commit 14d5c3a

Browse files
author
Seppo Takalo
committed
Do no garbage_collect() on init()
Previous logic caused garbage collection to kick in, if the init() was called on empty storage. This has effect of erasing areas twice, if both areas were empty. Re-write logic so that we erase areas only on garbage_collect() or reset(). The init() logic already chooses the active area, so no need to touch, until keys are modified. Removed also the is_erase_unit_erased() as this is working only on FLASH devices, and TDBStore should be refactored to work on all storages.
1 parent 2141526 commit 14d5c3a

File tree

2 files changed

+21
-84
lines changed

2 files changed

+21
-84
lines changed

features/storage/kvstore/tdbstore/TDBStore.cpp

Lines changed: 21 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ typedef struct {
6868

6969
typedef enum {
7070
TDBSTORE_AREA_STATE_NONE = 0,
71-
TDBSTORE_AREA_STATE_EMPTY,
71+
TDBSTORE_AREA_STATE_ERASED,
72+
TDBSTORE_AREA_STATE_INVALID,
7273
TDBSTORE_AREA_STATE_VALID,
7374
} area_state_e;
7475

@@ -831,6 +832,7 @@ int TDBStore::garbage_collection()
831832
int ret;
832833
size_t ind;
833834

835+
// Reset the standby area
834836
ret = reset_area(1 - _active_area);
835837
if (ret) {
836838
return ret;
@@ -866,12 +868,6 @@ int TDBStore::garbage_collection()
866868
return ret;
867869
}
868870

869-
// Now reset standby area
870-
ret = reset_area(1 - _active_area);
871-
if (ret) {
872-
return ret;
873-
}
874-
875871
return MBED_SUCCESS;
876872
}
877873

@@ -967,7 +963,7 @@ int TDBStore::init()
967963
uint32_t next_offset;
968964
uint32_t flags, hash;
969965
uint32_t actual_data_size;
970-
int os_ret, ret = MBED_SUCCESS, reserved_ret;
966+
int os_ret, ret = MBED_SUCCESS;
971967
uint16_t versions[_num_areas];
972968

973969
_mutex.lock();
@@ -1034,13 +1030,9 @@ int TDBStore::init()
10341030
MBED_ERROR(ret, "TDBSTORE: Unable to read record at init");
10351031
}
10361032

1037-
// Master record may be either corrupt or erased - either way erase it
1038-
// (this will do nothing if already erased)
1033+
// Master record may be either corrupt or erased
10391034
if (ret == MBED_ERROR_INVALID_DATA_DETECTED) {
1040-
if (reset_area(area)) {
1041-
MBED_ERROR(MBED_ERROR_READ_FAILED, "TDBSTORE: Unable to reset area at init");
1042-
}
1043-
area_state[area] = TDBSTORE_AREA_STATE_EMPTY;
1035+
area_state[area] = TDBSTORE_AREA_STATE_INVALID;
10441036
continue;
10451037
}
10461038

@@ -1055,9 +1047,11 @@ int TDBStore::init()
10551047
}
10561048

10571049
// In case we have two empty areas, arbitrarily use area 0 as the active one.
1058-
if ((area_state[0] == TDBSTORE_AREA_STATE_EMPTY) && (area_state[1] == TDBSTORE_AREA_STATE_EMPTY)) {
1050+
if ((area_state[0] == TDBSTORE_AREA_STATE_INVALID) && (area_state[1] == TDBSTORE_AREA_STATE_INVALID)) {
1051+
reset_area(0);
10591052
_active_area = 0;
10601053
_active_area_version = 1;
1054+
area_state[0] = TDBSTORE_AREA_STATE_ERASED;
10611055
ret = write_master_record(_active_area, _active_area_version, _free_space_offset);
10621056
if (ret) {
10631057
MBED_ERROR(ret, "TDBSTORE: Unable to write master record at init");
@@ -1067,58 +1061,31 @@ int TDBStore::init()
10671061
}
10681062

10691063
// In case we have two valid areas, choose the one having the higher version (or 0
1070-
// in case of wrap around). Reset the other one.
1064+
// in case of wrap around).
10711065
if ((area_state[0] == TDBSTORE_AREA_STATE_VALID) && (area_state[1] == TDBSTORE_AREA_STATE_VALID)) {
10721066
if ((versions[0] > versions[1]) || (!versions[0])) {
10731067
_active_area = 0;
10741068
} else {
10751069
_active_area = 1;
10761070
}
10771071
_active_area_version = versions[_active_area];
1078-
ret = reset_area(1 - _active_area);
1079-
if (ret) {
1080-
MBED_ERROR(ret, "TDBSTORE: Unable to reset area at init");
1081-
}
10821072
}
10831073

10841074
// Currently set free space offset pointer to the end of free space.
10851075
// Ram table build process needs it, but will update it.
10861076
_free_space_offset = _size;
10871077
ret = build_ram_table();
10881078

1079+
// build_ram_table() scans all keys, until invalid data found.
1080+
// Therefore INVALID_DATA is not considered error.
10891081
if ((ret != MBED_SUCCESS) && (ret != MBED_ERROR_INVALID_DATA_DETECTED)) {
1090-
MBED_ERROR(ret, "TDBSTORE: Unable to build RAM table at init");
1091-
}
1092-
1093-
if ((ret == MBED_ERROR_INVALID_DATA_DETECTED) && (_free_space_offset < _size)) {
1094-
// Space after last valid record may be erased, hence "corrupt". Now check if it really is erased.
1095-
bool erased;
1096-
if (is_erase_unit_erased(_active_area, _free_space_offset, erased)) {
1097-
MBED_ERROR(MBED_ERROR_READ_FAILED, "TDBSTORE: Unable to check whether erase unit is erased at init");
1098-
}
1099-
if (erased) {
1100-
// Erased - all good
1101-
ret = MBED_SUCCESS;
1102-
}
1103-
}
1104-
1105-
// If we either have a corrupt record somewhere
1106-
// perform garbage collection to salvage all preceding records.
1107-
if ((ret == MBED_ERROR_INVALID_DATA_DETECTED)) {
1108-
ret = garbage_collection();
1109-
if (ret) {
1110-
MBED_ERROR(ret, "TDBSTORE: Unable to perform GC at init");
1111-
}
1112-
os_ret = _buff_bd->sync();
1113-
if (os_ret) {
1114-
MBED_ERROR(MBED_ERROR_WRITE_FAILED, "TDBSTORE: Unable to sync BD at init");
1115-
}
1082+
goto fail;
11161083
}
11171084

11181085
end:
11191086
_is_initialized = true;
11201087
_mutex.unlock();
1121-
return ret;
1088+
return MBED_SUCCESS;
11221089
fail:
11231090
delete[] ram_table;
11241091
delete _buff_bd;
@@ -1348,6 +1315,13 @@ int TDBStore::reserved_data_set(const void *reserved_data, size_t reserved_data_
13481315
trailer.data_size = reserved_data_buf_size;
13491316
trailer.crc = calc_crc(initial_crc, reserved_data_buf_size, reserved_data);
13501317

1318+
// Erase the header of non-active area, just to make sure that we can write to it
1319+
// In case garbage collection has not yet been run, the area can be un-erased
1320+
ret = reset_area(1 - _active_area);
1321+
if (ret) {
1322+
goto end;
1323+
}
1324+
13511325
/*
13521326
* Write to both areas
13531327
* Both must success, as they are required to be erased when TDBStore initializes
@@ -1451,35 +1425,10 @@ void TDBStore::offset_in_erase_unit(uint8_t area, uint32_t offset,
14511425
dist_to_end = _buff_bd->get_erase_size(agg_offset) - offset_from_start;
14521426
}
14531427

1454-
int TDBStore::is_erase_unit_erased(uint8_t area, uint32_t offset, bool &erased)
1455-
{
1456-
uint32_t offset_from_start, dist;
1457-
offset_in_erase_unit(area, offset, offset_from_start, dist);
1458-
uint8_t buf[sizeof(record_header_t)], blanks[sizeof(record_header_t)];
1459-
memset(blanks, _buff_bd->get_erase_value(), sizeof(blanks));
1460-
1461-
while (dist) {
1462-
uint32_t chunk = std::min(dist, (uint32_t) sizeof(buf));
1463-
int ret = read_area(area, offset, chunk, buf);
1464-
if (ret) {
1465-
return MBED_ERROR_READ_FAILED;
1466-
}
1467-
if (memcmp(buf, blanks, chunk)) {
1468-
erased = false;
1469-
return MBED_SUCCESS;
1470-
}
1471-
offset += chunk;
1472-
dist -= chunk;
1473-
}
1474-
erased = true;
1475-
return MBED_SUCCESS;
1476-
}
1477-
14781428
int TDBStore::check_erase_before_write(uint8_t area, uint32_t offset, uint32_t size, bool force_check)
14791429
{
14801430
// In order to save init time, we don't check that the entire area is erased.
14811431
// Instead, whenever reaching an erase unit start erase it.
1482-
14831432
while (size) {
14841433
uint32_t dist, offset_from_start;
14851434
int ret;
@@ -1497,4 +1446,3 @@ int TDBStore::check_erase_before_write(uint8_t area, uint32_t offset, uint32_t s
14971446
}
14981447
return MBED_SUCCESS;
14991448
}
1500-

features/storage/kvstore/tdbstore/TDBStore.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -500,17 +500,6 @@ class TDBStore : public KVStore {
500500
void offset_in_erase_unit(uint8_t area, uint32_t offset, uint32_t &offset_from_start,
501501
uint32_t &dist_to_end);
502502

503-
/**
504-
* @brief Check whether erase unit is erased (from offset until end of unit).
505-
*
506-
* @param[in] area Area.
507-
* @param[in] offset Offset in area.
508-
* @param[out] erased Unit is erased.
509-
*
510-
* @returns 0 for success, nonzero for failure.
511-
*/
512-
int is_erase_unit_erased(uint8_t area, uint32_t offset, bool &erased);
513-
514503
/**
515504
* @brief Before writing a record, check whether you are crossing an erase unit.
516505
* If you do, check if it's erased, and erase it if not.

0 commit comments

Comments
 (0)