Skip to content

Fix redundant save on every Entity.load() — eliminates unnecessary json.dumps + storage write #1

@deucalioncodes

Description

@deucalioncodes

Problem

Every Entity.load() call triggers a full re-serialization and write-back of the entity to storage, even though nothing has changed.

Current load path

storage.get → json.loads → Entity.__init__(**data, _loaded=True) → _save() → serialize() → json.dumps → storage.insert

In __init__, after setting all attributes with _do_not_save=True, the flag is reset and _save() is called unconditionally:

self._do_not_save = True
for k, v in kwargs.items():
    if not k.startswith("_"):
        setattr(self, k, v)
self._do_not_save = False

self._save()  # always runs, even when _loaded=True

_save() then unconditionally serializes and writes back:

data = self.serialize()

if not self._do_not_save:
    db.save(self._type, self._id, persisted_data)  # json.dumps + storage.insert

Impact per load

  • 1x json.loads (read from storage)
  • 1x serialize() (Python dict construction, MRO walk)
  • 1x json.dumps (redundant write-back)
  • 1x storage.insert (redundant StableBTreeMap write on canister)
  • 1x audit json.dumps (if audit enabled)

That is 3 JSON round-trips + 1 storage write for a read-only operation.

Fix

In __init__, skip _save() when loading an existing entity:

if not self._loaded:
    self._save()

This eliminates the redundant serialize + write on every load, cutting JSON overhead roughly in half for read-heavy workloads.

Notes

  • The entity registry and context tracking still happen — only the redundant DB write is skipped.
  • When _loaded=True, the data in storage is already up-to-date (we just read it), so writing it back is a no-op with wasted cycles.
  • On IC canisters, each storage.insert hits a StableBTreeMap, so the cost is non-trivial.
  • Benchmark tests exist in tests/src/tests/test_benchmark.py to measure before/after impact.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions