8000 [kyo-system, kyo-system-doltfs] hold every write backend to the host's placement and creation rules by DamianReeves · Pull Request #2203 · getkyo/kyo · GitHub
[go: up one dir, main page]

Skip to content

[kyo-system, kyo-system-doltfs] hold every write backend to the host's placement and creation rules - #2203

Open
DamianReeves wants to merge 1 commit into
mainfrom
dolt-filesystem-contract
Open

DamianReeves wants to merge 1 commit into
mainfrom
dolt-filesystem-contract

Conversation

@DamianReeves
Copy link
Copy Markdown
Collaborator

Problem

DoltFileSystem (#1956) passed the write tier of kyo-system-conformance, but the tier did not test several rules the host already follows. Against those rules, Dolt had six defects:

  • A write beneath a regular file created an entry under it.
  • Writes did not follow links. A write through a linked directory landed beside the link, where reads never look, and a write to a link replaced the link with a file.
  • WriteOpen.CreateNew checked for the file, then wrote it, so several concurrent openers all succeeded.
  • A move cleared the target and placed the source in separate statements. A reader in between saw no target, even with Atomicity.Required.
  • A replacing move or copy deleted a directory that still had entries.
  • A move or copy of an entry onto itself deleted the entry.

The host also had smaller gaps:

  • A move or copy refused by its target named the source in the failure.
  • Scala Native's Files.move and Files.copy do not apply the JDK's rule for a directory target. Node's error for that case varies by operating system.

Solution

The write tier gains these laws, so every backend is held to them:

  • A write beneath a regular file fails and leaves the file unchanged.
  • A reader racing a required atomic move sees the old content or the new one, never no target.
  • Of eight concurrent create-new opens, exactly one succeeds and seven fail with FileAlreadyExistsException.
  • A replacing move or copy onto a directory with entries fails with FileDirectoryNotEmptyException naming that directory. An empty directory is replaced.
  • A non-replacing move or copy names the existing target in its FileAlreadyExistsException.

Each law failed against Dolt before this change, and the host passes all of them.

Dolt:

  • Writes resolve links as the host does. Content operations (write, append, truncate, set modification time, channels) follow every link. Entry operations (mkDir, mkFile, symlink, remove, and the move or copy target) follow the links in the parent path and act on the entry itself. Create-new does not follow a link at the path, matching an exclusive host open.
  • An existing parent that is not a directory refuses the entry, with the host's failure shape: FileIOException naming the entry.
  • Creation is one insert keyed by the path, which is the table's primary key. A concurrent creator that loses is refused.
  • move runs in one transaction. Every check runs before the first write and reports failure as a value, because the pool discards a session that a non-engine failure crosses. Over an in-memory DoltLite database, that would discard the database.
  • A move or copy onto itself is a no-op.

Host:

  • move and copy name the target when the target is what refused them.
  • On JVM, Native, JS, and Wasm, a replacing move or copy refuses a directory with entries and replaces an empty one. Under Atomicity.Required it does not remove a directory first, since that would split the replacement in two.

Notes

…s placement and creation rules

The write tier gains laws the host already met and the Dolt filesystem
did not. Each new law failed against Dolt before this change.

Dolt filesystem:
- A write beneath a regular file created an entry under it. It now
  fails as the host does, with an I/O failure naming the entry.
- Writes did not follow links. A write through a linked directory
  landed beside the link, where reads never look, and a write to a link
  replaced it with a file. Content operations now follow every link,
  and entry operations follow the links in the parent path.
- Create-new checked, then wrote, so concurrent openers all succeeded.
  Creation is now one insert keyed by the path, so exactly one wins.
- A move cleared the target and placed the source in separate
  statements, so a reader saw no target in between. It now runs in one
  transaction. Its checks report failures as values, since the pool
  discards a session that a failure crosses.
- A replacing move or copy deleted a directory with entries. It now
  fails with FileDirectoryNotEmptyException.
- A move or copy of an entry onto itself deleted it. It is now a no-op.

Host:
- A move or copy refused by its target named the source. It now names
  the target.
- Scala Native's move and copy did not apply the JDK's rule for a
  directory target, and Node's error for it varies by operating system.
  All hosts now refuse a directory with entries and replace an empty
  one, except under required atomicity.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0