My intention is to create a big chunk of file, like 1G, or 10G, and
store data into it to minimize disk fragmentation, and minimize file
seek operation during reading.
Truncate... hmm, strange naming. I know it's legacy. Anyway, as long
as it works. Thanks!
Chris
can you explain a bit more what you expect?
with xfs i've been doing this for a long time now, with recent linux
kernels you can do it on some other fs' as well
truncate will not allocate the space for you, is you populate the data
it wil fragment (which might be fine)
The idea of Haystack is to minimize disk operation. A fragmented file
will have extra disk seeks.
However, I still want to support multiple writing operations, which
would cause some disk fragmentation.
So I would like the file system to pre-allocate continuous spaces with
best effort.
I see os.File.Truncate calls syscall.Ftruncate. Seems it just set the
high watermark without really allocating the space, or the behavior
varies on different file systems? (btw, Facebook Haystack did use
XFS.)
Chris
Having said that, the underlying properties of your filesystem will have a strong impact on how successful this approach is.
Cheers
Dave
Sent from my iPhone
it's slow and tends to thrash the page-cache
> Calls to ftruncate and friends will be faster on paper, but they
> don't actually write blocks to disk so they will theoretically
> fragment when the OS seeks into the file.
xfs tracks preallocate _unwritten_ space
prealloc hack:
$ make prealloc
co RCS/prealloc.go,v prealloc.go
RCS/prealloc.go,v --> prealloc.go
revision 1.7
done
6g -o prealloc.6 prealloc.go
6l -o prealloc prealloc.6
rm prealloc.go prealloc.6
making a pre-allocated file:
$ time ./prealloc -size=8G test-file
real 0m0.003s
user 0m0.000s
sys 0m0.000s
3ms to create an 8G file, but larger isn't much slower (if at all)
$ xfs_bmap -vp test-file
test-file:
EXT: FILE-OFFSET BLOCK-RANGE AG AG-OFFSET TOTAL FLAGS
0: [0..16777215]: 207833688..224610903 0 (207833688..224610903) 16777216 10000
so we have one unwritten-data extent
write data over some if that (& sync to flush delalloc)
$ xfs_bmap -vp test-file
test-file:
EXT: FILE-OFFSET BLOCK-RANGE AG AG-OFFSET TOTAL FLAGS
0: [0..524287]: 207833688..208357975 0 (207833688..208357975) 524288 00000
1: [524288..16777215]: 208357976..224610903 0 (208357976..224610903) 16252928 10000
the one extend is split into two, once written (flags 00000) and one
unwritten (flags 10000), but they are adjacent
the prealloc code is a crude syscall wrapper ioctl:
func prealloc(f *os.File, length int64) {
fl := &blkstat.XFS_flock64{Len: length}
r0, _, errptr := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(f.Fd()),
uintptr(blkstat.XFS_IOC_RESVSP64),
uintptr(unsafe.Pointer(fl)))
if int(r0) == -1 {
fatal("Error (prealloc): %s\n", errptr)
}
}
(this is fairly non-Go specific at this point, if you want more
details contact me off list)
for recent linux kernels there is posix_fallocate which is passed down
to the fs where it's free to do (usually) a pretty good job
the xfs ioctl's i'm using do the same thing (but are much much older)