update mutable file API: overwrite vs replace, expose verinfo? #328
Labels
No Label
0.2.0
0.3.0
0.4.0
0.5.0
0.5.1
0.6.0
0.6.1
0.7.0
0.8.0
0.9.0
1.0.0
1.1.0
1.10.0
1.10.1
1.10.2
1.10a2
1.11.0
1.12.0
1.12.1
1.13.0
1.14.0
1.15.0
1.15.1
1.2.0
1.3.0
1.4.1
1.5.0
1.6.0
1.6.1
1.7.0
1.7.1
1.7β
1.8.0
1.8.1
1.8.2
1.8.3
1.8β
1.9.0
1.9.0-s3branch
1.9.0a1
1.9.0a2
1.9.0b1
1.9.1
1.9.2
1.9.2a1
LeastAuthority.com automation
blocker
cannot reproduce
cloud-branch
code
code-dirnodes
code-encoding
code-frontend
code-frontend-cli
code-frontend-ftp-sftp
code-frontend-magic-folder
code-frontend-web
code-mutable
code-network
code-nodeadmin
code-peerselection
code-storage
contrib
critical
defect
dev-infrastructure
documentation
duplicate
enhancement
fixed
invalid
major
minor
n/a
normal
operational
packaging
somebody else's problem
supercritical
task
trivial
unknown
was already fixed
website
wontfix
worksforme
No Milestone
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Reference: tahoe-lafs/trac-2024-07-25#328
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
In the #321 analysis, we discovered that the mutable file API
(!IMutableFileNode) is not doing quite what we want it to do. The intention
was to make sure that the application was aware of any changes to the file:
no automatic merges. That means that a user of the mutable file (such as a
dirnode) that sees version 3, then changes the contents to add some child
entry and writes out the new version as 4, should receive an error if the
mutable file node sees evidence of some other version 4.
We expect code to use the mutable file node like this:
but what's not obvious from this code is that the mutable file node remembers
the version information (seqnum and roothash) internally. The preceding code
sample suggests that the
replace
call will use this internal cache asthe update precondition, thereby throwing an exception if a newer version is
already present in the grid.
However, we learned that
replace
is actually doing a retrieve first,then doing a publish. This has the effect of ignoring the
previously-retrieved version verinfo, transforming our
replace
callinto an
overwrite
.We thought of two API changes to fix this. The first is to make distinct
replace
andoverwrite
calls.replace
would be used asabove, with a requirement that
n.download_to_data
must be called first(under penalty of raising an exception). The verinfo retrieved with
download_to_data
would be used as the precondition for thereplace
. The separateoverwrite
call would not require apreceding
download_to_data
, instead it would do an internal retrieval(to discover what seqnum it should use) then turn around and do a publish
with the replacement contents. We would expect
overwrite
to be usedvery rarely, since it makes data loss the norm rather than the exception.
The other approach would be to expose the verinfo to the application, and ask
it to pass that information back in at publish time. By making it explicit
instead of staying hidden inside the mutable file node, the verinfo data
could be passed to and from an external client (i.e. over HTTP, perhaps in
JSON or through some special HTTP header like !ETag). In this case,
download
ordownload_to_data
would fire with a tuple of (verinfo,contents), and
replace
would accept (verinfo, newcontents).If we were also to pass the sharemap from the retrieve side to the publish
side, we could avoid a roundtrip at publish time (by using the previous
sharemap as a precondition). This would shave about 200-250ms off the update
time, which represents about 40% of a small-dirnode publish, and perhaps 10%
of a large one. Another small speedup would be achieved by stashing the
encrypted privkey at retrieve time, perhaps 5-10%, but it should be kept
hidden inside the node rather than being passed through the application.
I don't know which approach is better. A lot of it depends upon what you
think of as the application, and where you are comfortable with "automatic
merges". It probably comes down to whether or not the HTTP "add child to
directory" command is supposed to overwrite an existing child or not.
add_child is pretty safe as it is: the only chance of surprise/dataloss is if
someone else added a child of the same name while you weren't looking, in
which case you'll overwrite it. This could be considered an automatic merge
of the add request.
We're planning (#205) to refactor Retrieve to make it easier for use in
checking (by returning multiple versions, and information about versions that
it couldn't decode). We should probably decide on this issue before doing
that refactoring.
The (internal) mutable file API has been overhauled, and should support at least some of this stuff. Take a look at the
IMutableFileNode
API in source:src/allmydata/interfaces.py#L568 .An open question is how much to expose this to the outside world (through the webapi). The only way an external client can currently use mutable files is by blindly overwriting them. If those clients want to put structured data in a mutable file and perform controlled updates, then they'll need the same sort of test-modify-set semantics as they could get inside the tahoe process by passing a servermap around.
But I don't think that passing a servermap outside the tahoe node is a good idea (although maybe passing a handle to one could work).
There's much to discuss about this one. But I think about half of this ticket could be closed now.
I've created #413 to track the possibility of exposing the servermaps and version info in general to HTTP clients. Time to close this one.