>
> To be honest I'm not sure if I've ever used kj::File to load 
> Cap'n-Proto-format data. The file API was sort of built for other things I 
> was doing that happened to be built on KJ.
>
That's the impression I got too.

> But if I were using it, I think I'd do:
> - Reads always using mmap(), not streams. You'll need a reinterpret_cast 
> to get an ArrayPtr<capnp::word>, but no shims needed here.
>
FsNode::mmap()? I'll try it if I ever need to rewrite the file saving code. 

> - Writes probably using Directory::appendFile() to open the file for 
> appending. This gives you an OutputStream so you can directly use 
> capnp::writeMessage(), no shims needed.
>
I looked into this, but decided to use Directory::replaceFile() because I 
wanted atomic saving. However, Directory::replaceFile() doesn't support 
returning an AppendableFile.

> > And newFileAppender() is a *bad* idea since it calls stat() on every 
> single file write to query the current length
>
> I don't understand what you mean here. kj::newFileAppender() is explicitly 
> documented as not doing this, with the caveat that it won't work correctly 
> if there are multiple concurrent appenders. On the other hand, if you use 
> Directory::appendFile() to open the file, then it uses the O_APPEND flag 
> which makes it the operating system's job to ensure all bytes are appended 
> -- no need for stat().
>
In the context of Cap'n Proto, concurrent writes result in a corrupted file 
no matter what behavior is used. And capnp's write methods take a 
kj::[Buffered]OutputStream&, 
and OutputStream is inherited by AppendableFile but not File, and the 
easiest way to get an AppendableFile from a File calls stat() on every 
write (the hard way is to write a subclass of OutputStream... just found 
out I only need to subclass OutputStream, not AppendableFile). I suppose 
each piece of the puzzle is understandable, but the end result is 
unfortunate. Maybe AppendableFile guarantees that interleaved writes within 
or between processes are interleaved and don't overwrite (resulting in 
newFileAppender()'s 
design), but Cap'n Proto instead expects that no interleaved writes exist 
at all during writing.

If I remember correctly, I decided against writing to fd integers because 
they seemed less supported on Windows than Linux, and required different 
APIs per OS as well, and supporting arbitrary paths on Windows requires 
16-bit characters while Linux requires 8-bit characters (whereas 
kj::Filesystem handles this using transparent WTF-8 conversion). I could've 
instead used open() and _wopen() (or _wsopen_s() to satisfy Microsoft's API 
deprecations) rather than kj filesystem operations, and on Windows 
converted WTF-8 to UTF-16 like kj does. (Of course it would be easier to 
use narrow characters on Windows, but depending on the codepage it might 
fail to support unpaired UTF-16 surrogates or even Unicode altogether.) I'd 
still need to build a cross-platform atomic-save library, perhaps with 
C++'s std::filesystem, but its char/wchar handling is scary (though perhaps 
std::filesystem::u8path or path(char8_t) would work).

-- 
You received this message because you are subscribed to the Google Groups 
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to capnproto+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/capnproto/a368d1b6-ff73-44ae-8af2-e91bdd862415n%40googlegroups.com.

Reply via email to