Problem
OSW.fetch_schema enables the page cache and fails to restore the previous
state when it is called with more than one schema title. The cache stays enabled
for the rest of the process. A later get_page can then return a revision from
before a write that happened in between.
Mechanism
fetch_schema processes the titles one at a time. Each invocation does this at
https://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L598:
site_cache_state = self.site.get_cache_enabled()
self.site.enable_cache()
site_cache_state is a local variable of that invocation. The restore is
guarded by final at
https://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L1057:
if fetchSchemaParam.final:
importlib.reload(model)
if not site_cache_state:
self.site.disable_cache() # restore original state
final is set per title at
https://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L500-L508:
last = schema_title == fetchSchemaParam.schema_title[-1]
...
final=last
With two or more titles the sequence is:
- First title: snapshot
False (cache disabled), enable the cache.
- Second title: snapshot
True, because the first invocation already enabled
it. Enable again.
- Last title:
final is True, so the restore runs. But its own snapshot is
True, so if not site_cache_state is false and disable_cache is never
called.
The cache is left enabled. Only the single-title case restores correctly.
There is a second path with the same result: the early return for a missing
schema page at
https://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L621
returns before the restore, so if that title is the last one the restore is
skipped entirely.
Measured consequence
On osl.dev.afin-data.de at commit 9aa6322, a sequence of two update_task
calls against the same page reverted the status from "Done" back to "To do".
The second call read the page through the leaked cache, received the
pre-update jsondata, and wrote that stale content back.
Any code that reads an entity, modifies it and stores it is exposed to this,
because fetch_schema runs implicitly during ordinary read and write calls.
Suggested fix
Snapshot the cache state once for the whole fetch_schema operation rather than
once per title, and restore it in a finally block so the early returns cannot
skip it.
Related
#141 reports a different
side effect of the same implicit fetch_schema call: it rewrites
src/osw/model/entity.py. The two are separate defects in the same code path.
Problem
OSW.fetch_schemaenables the page cache and fails to restore the previousstate when it is called with more than one schema title. The cache stays enabled
for the rest of the process. A later
get_pagecan then return a revision frombefore a write that happened in between.
Mechanism
fetch_schemaprocesses the titles one at a time. Each invocation does this athttps://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L598:
site_cache_stateis a local variable of that invocation. The restore isguarded by
finalathttps://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L1057:
finalis set per title athttps://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L500-L508:
With two or more titles the sequence is:
False(cache disabled), enable the cache.True, because the first invocation already enabledit. Enable again.
finalisTrue, so the restore runs. But its own snapshot isTrue, soif not site_cache_stateis false anddisable_cacheis nevercalled.
The cache is left enabled. Only the single-title case restores correctly.
There is a second path with the same result: the early return for a missing
schema page at
https://github.com/OpenSemanticLab/osw-python/blob/9aa6322/src/osw/core.py#L621
returns before the restore, so if that title is the last one the restore is
skipped entirely.
Measured consequence
On
osl.dev.afin-data.deat commit 9aa6322, a sequence of twoupdate_taskcalls against the same page reverted the status from "Done" back to "To do".
The second call read the page through the leaked cache, received the
pre-update
jsondata, and wrote that stale content back.Any code that reads an entity, modifies it and stores it is exposed to this,
because
fetch_schemaruns implicitly during ordinary read and write calls.Suggested fix
Snapshot the cache state once for the whole
fetch_schemaoperation rather thanonce per title, and restore it in a
finallyblock so the early returns cannotskip it.
Related
#141 reports a different
side effect of the same implicit
fetch_schemacall: it rewritessrc/osw/model/entity.py. The two are separate defects in the same code path.