Skip to content

fix(io): sync local files to disk before the catalog commit - #4146

Open
ghoshp83 wants to merge 1 commit into
apache:mainfrom
ghoshp83:local-fs-sync-on-close
Open

ghoshp83 wants to merge 1 commit into
apache:mainfrom
ghoshp83:local-fs-sync-on-close

Conversation

@ghoshp83

Copy link
Copy Markdown

Closes #4145.

Rationale for this change

PyArrowFileIO writes local (file://) files through pyarrow.fs.LocalFileSystem, whose output stream never calls fsync. The catalog then commits a pointer to the new metadata.json, so after a power loss the pointer can survive while the files it references are empty, and the table no longer loads. #4145 has the full trace and a power-cut reproduction.

This change makes a local write durable when its stream is closed, which is before any catalog commit can reference it:

  • PyArrowLocalFileSystem.open_output_stream now returns _SyncOnCloseOutputStream, a pyarrow.BufferedOutputStream over a pyarrow.OSFile. On close() it flushes, fsyncs the file, and then fsyncs the parent directory so that the new entry is durable too.
  • When open_output_stream has to create parent directories (for example metadata/ or data/ on the first write), it also fsyncs the parent of each directory it created.

The stream stays a native pyarrow stream with the same buffer size, so the Parquet, Avro and metadata writers are unchanged. Every caller already closes its stream explicitly or through with.

Scope, kept deliberately narrow:

The cost is two fsync calls per written file, and only on a local warehouse. Object stores are not affected. I have not added a property to turn this off. If you would like one, I can add it.

Are these changes tested?

Yes. test_pyarrow_local_fs_syncs_file_and_new_directories_on_close writes through PyArrowFileIO into a path whose parent directories do not exist yet. It then checks that the file and the three directories whose entries changed were synced, by comparing the inodes of the fsynced descriptors.

Are there any user-facing changes?

There is no API change. Writes to a local warehouse are now durable once a commit returns, at the cost of the fsync calls above.

PyArrowFileIO wrote local files without fsync, so a power loss after an acknowledged commit could leave the catalog pointing at an empty metadata.json. Flush each file and its directory entry to disk when the stream is closed.

@rambleraptor rambleraptor left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you able to give any benchmarks on performance for this? This seems like a bit of an edge case and I'm worried that we're introducing latency on a per-file basis.

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

2 participants