Skip to content

Commit

Permalink
Limit the maximum size of ledger data
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeuz committed Jul 4, 2023
1 parent 8344b68 commit 2246615
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 27 deletions.
5 changes: 3 additions & 2 deletions services/inc/system_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@
(LEDGER_UNSUPPORTED_FORMAT, "Unsupported format of ledger data", -2003), \
(LEDGER_READ_ONLY, "Ledger is read only", -2004), \
(LEDGER_IN_USE, "Ledger is in use", -2005), \
(LEDGER_SERIALIZATION, "Ledger serialization error", -2006), \
(LEDGER_DESERIALIZATION, "Ledger deserialization error", -2007)
(LEDGER_TOO_LARGE, "Ledger data is too large", -2006), \
(LEDGER_SERIALIZATION, "Ledger serialization error", -2007), \
(LEDGER_DESERIALIZATION, "Ledger deserialization error", -2008)

// Expands to enum values for all errors
#define SYSTEM_ERROR_ENUM_VALUES(prefix) \
Expand Down
8 changes: 7 additions & 1 deletion system/inc/system_ledger.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
*/
#define LEDGER_API_VERSION 1

/**
* Maximum size of ledger data.
*/
#define LEDGER_MAX_DATA_SIZE 16384

/**
* Ledger instance.
*/
Expand Down Expand Up @@ -122,8 +127,9 @@ typedef struct ledger_info {
* If 0, the ledger has never been synchronized.
*/
int64_t last_synced;
int sync_direction; ///< Synchronization direction as defined by the `ledger_sync_direction` enum.
size_t data_size; ///< Size of the ledger data.
int scope; ///< Ledger scope as defined by the `ledger_scope` enum.
int sync_direction; ///< Synchronization direction as defined by the `ledger_sync_direction` enum.
int flags; ///< Flags defined by the `ledger_info_flag` enum.
} ledger_info;

Expand Down
5 changes: 3 additions & 2 deletions system/src/system_ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ int ledger_get_info(ledger_instance* ledger, ledger_info* info, void* reserved)
auto lr = reinterpret_cast<Ledger*>(ledger);
auto srcInfo = lr->info();
info->name = lr->name();
info->scope = srcInfo.scope();
info->sync_direction = srcInfo.syncDirection();
info->last_updated = srcInfo.lastUpdated();
info->last_synced = srcInfo.lastSynced();
info->data_size = srcInfo.dataSize();
info->scope = srcInfo.scope();
info->sync_direction = srcInfo.syncDirection();
info->flags = 0;
if (srcInfo.syncPending()) {
info->flags |= LEDGER_INFO_SYNC_PENDING;
Expand Down
68 changes: 49 additions & 19 deletions system/src/system_ledger_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ Ledger::Ledger() :
stagedFileCount_(0),
lastUpdated_(0),
lastSynced_(0),
dataSize_(0),
syncPending_(false),
syncCallback_(nullptr),
destroyAppData_(nullptr),
Expand Down Expand Up @@ -441,6 +442,7 @@ LedgerInfo Ledger::info() const {
return LedgerInfo()
.scope(scope_)
.syncDirection(syncDir_)
.dataSize(dataSize_)
.lastUpdated(lastUpdated_)
.lastSynced(lastSynced_)
.syncPending(syncPending_);
Expand Down Expand Up @@ -513,25 +515,23 @@ int Ledger::endWrite(LedgerWriter* writer, const LedgerInfo& info) {
}
});
// Update the ledger info
auto oldInfo = this->info();
updateLedgerInfo(info);
if (!info.hasSyncPending() && writer->changeSource() == LedgerChangeSource::USER) {
syncPending_ = true;
}
auto newInfo = this->info().update(info);
newInfo.dataSize(writer->dataSize());
if (!info.hasLastUpdated()) {
lastUpdated_ = 0; // Time is unknown
int64_t time = 0; // Time is unknown
if (hal_rtc_time_is_valid(nullptr)) {
timeval tv = {};
if (hal_rtc_get_time(&tv, nullptr) >= 0) {
lastUpdated_ = tv.tv_sec * 1000ll + tv.tv_usec / 1000;
time = tv.tv_sec * 1000ll + tv.tv_usec / 1000;
}
}
newInfo.lastUpdated(time);
}
if (!info.hasSyncPending() && writer->changeSource() == LedgerChangeSource::USER) {
newInfo.syncPending(true);
}
NAMED_SCOPE_GUARD(restoreInfoGuard, {
updateLedgerInfo(oldInfo);
});
// Write the info section
size_t infoSize = CHECK(writeLedgerInfo(fs.instance(), file));
size_t infoSize = CHECK(writeLedgerInfo(fs.instance(), file, newInfo));
// Write the header
CHECK_FS(lfs_file_seek(fs.instance(), file, 0, LFS_SEEK_SET));
CHECK(writeDataHeader(fs.instance(), file, writer->dataSize(), infoSize));
Expand Down Expand Up @@ -561,7 +561,7 @@ int Ledger::endWrite(LedgerWriter* writer, const LedgerInfo& info) {
stagedSeqNum_ = writer->seqNumber();
++stagedFileCount_;
}
restoreInfoGuard.dismiss();
updateLedgerInfo(newInfo);
return 0;
}

Expand Down Expand Up @@ -628,17 +628,17 @@ int Ledger::loadLedgerInfo(lfs_t* fs) {
return 0;
}

int Ledger::writeLedgerInfo(lfs_t* fs, lfs_file_t* file) {
int Ledger::writeLedgerInfo(lfs_t* fs, lfs_file_t* file, const LedgerInfo& info) {
PB_INTERNAL(LedgerInfo) pbInfo = {};
size_t n = strlcpy(pbInfo.name, name_, sizeof(pbInfo.name));
if (n >= sizeof(pbInfo.name)) {
return SYSTEM_ERROR_INTERNAL; // The name is longer than specified in ledger.proto
}
pbInfo.scope = static_cast<PB_LEDGER(LedgerScope)>(scope_);
pbInfo.sync_direction = static_cast<PB_LEDGER(SyncDirection)>(syncDir_);
pbInfo.last_updated = lastUpdated_;
pbInfo.last_synced = lastSynced_;
pbInfo.sync_pending = syncPending_;
pbInfo.scope = static_cast<PB_LEDGER(LedgerScope)>(info.scope());
pbInfo.sync_direction = static_cast<PB_LEDGER(SyncDirection)>(info.syncDirection());
pbInfo.last_updated = info.lastUpdated();
pbInfo.last_synced = info.lastSynced();
pbInfo.sync_pending = info.syncPending();
n = CHECK(encodeProtobufToFile(file, &PB_INTERNAL(LedgerInfo_msg), &pbInfo));
return n;
}
Expand All @@ -650,6 +650,9 @@ void Ledger::updateLedgerInfo(const LedgerInfo& info) {
if (info.hasSyncDirection()) {
syncDir_ = info.syncDirection();
}
if (info.hasDataSize()) {
dataSize_ = info.dataSize();
}
if (info.hasLastUpdated()) {
lastUpdated_ = info.lastUpdated();
}
Expand All @@ -676,7 +679,7 @@ int Ledger::initCurrentData(lfs_t* fs) {
// Reserve space for the header
CHECK_FS(lfs_file_seek(fs, &file, sizeof(LedgerDataHeader), LFS_SEEK_SET));
// Write the info section
size_t infoSize = CHECK(writeLedgerInfo(fs, &file));
size_t infoSize = CHECK(writeLedgerInfo(fs, &file, info()));
// Write the header
CHECK_FS(lfs_file_seek(fs, &file, 0, LFS_SEEK_SET));
CHECK(writeDataHeader(fs, &file, 0 /* dataSize */, infoSize));
Expand Down Expand Up @@ -762,6 +765,28 @@ int Ledger::removeTempData(lfs_t* fs) {
return 0;
}

LedgerInfo& LedgerInfo::update(const LedgerInfo& info) {
if (info.hasScope()) {
scope_ = info.scope();
}
if (info.hasSyncDirection()) {
syncDir_ = info.syncDirection();
}
if (info.hasDataSize()) {
dataSize_ = info.dataSize();
}
if (info.hasLastUpdated()) {
lastUpdated_ = info.lastUpdated();
}
if (info.hasLastSynced()) {
lastSynced_ = info.lastSynced();
}
if (info.hasSyncPending()) {
syncPending_ = info.syncPending();
}
return *this;
}

int LedgerReader::read(char* data, size_t size) {
if (!open_) {
return SYSTEM_ERROR_INVALID_STATE;
Expand Down Expand Up @@ -800,6 +825,11 @@ int LedgerWriter::write(const char* data, size_t size) {
if (!open_) {
return SYSTEM_ERROR_INVALID_STATE;
}
if (dataSize_ + size > LEDGER_MAX_DATA_SIZE) {
LOG(ERROR, "Size of ledger data exceeds the limit");
discard();
return SYSTEM_ERROR_LEDGER_TOO_LARGE;
}
FsLock fs;
size_t n = CHECK_FS(lfs_file_write(fs.instance(), &file_, data, size));
dataSize_ += n;
Expand Down
24 changes: 21 additions & 3 deletions system/src/system_ledger_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class Ledger: public LedgerBase {

int64_t lastUpdated_; // Last time the ledger was updated
int64_t lastSynced_; // Last time the ledger was synchronized
size_t dataSize_; // Size of the ledger data
bool syncPending_; // Whether the ledger has local changes that have not yet been synchronized

ledger_sync_callback syncCallback_; // Callback to invoke when the ledger has been synchronized
Expand All @@ -159,7 +160,7 @@ class Ledger: public LedgerBase {
int discardWrite(LedgerWriter* writer); // ditto

int loadLedgerInfo(lfs_t* fs);
int writeLedgerInfo(lfs_t* fs, lfs_file_t* file);
int writeLedgerInfo(lfs_t* fs, lfs_file_t* file, const LedgerInfo& info);
void updateLedgerInfo(const LedgerInfo& info);

int initCurrentData(lfs_t* fs);
Expand Down Expand Up @@ -200,6 +201,19 @@ class LedgerInfo {
return syncDir_.has_value();
}

LedgerInfo& dataSize(size_t size) {
dataSize_ = size;
return *this;
}

size_t dataSize() const {
return dataSize_.value_or(0);
}

bool hasDataSize() const {
return dataSize_.has_value();
}

LedgerInfo& lastUpdated(int64_t time) {
lastUpdated_ = time;
return *this;
Expand Down Expand Up @@ -239,11 +253,15 @@ class LedgerInfo {
return syncPending_.has_value();
}

LedgerInfo& update(const LedgerInfo& info);

private:
std::optional<ledger_scope> scope_;
std::optional<ledger_sync_direction> syncDir_;
// When adding new fields, make sure to update LedgerInfo::update() and Ledger::updateLedgerInfo()
std::optional<int64_t> lastUpdated_;
std::optional<int64_t> lastSynced_;
std::optional<size_t> dataSize_;
std::optional<ledger_scope> scope_;
std::optional<ledger_sync_direction> syncDir_;
std::optional<bool> syncPending_;
};

Expand Down
7 changes: 7 additions & 0 deletions wiring/inc/spark_wiring_ledger.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ class Ledger {
*/
time64_t lastSynced() const;

/**
* Get the size of the ledger data in bytes.
*
* @return Data size.
*/
size_t dataSize() const;

/**
* Get the ledger name.
*
Expand Down
8 changes: 8 additions & 0 deletions wiring/src/spark_wiring_ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ time64_t Ledger::lastSynced() const {
return info.last_synced;
}

size_t Ledger::dataSize() const {
ledger_info info = {};
if (!isValid() || getLedgerInfo(instance_, info) < 0) {
return 0;
}
return info.data_size;
}

const char* Ledger::name() const {
ledger_info info = {};
if (!isValid() || getLedgerInfo(instance_, info) < 0) {
Expand Down

0 comments on commit 2246615

Please sign in to comment.