allocate a big file extent

842 views
Skip to first unread message

Chris Lu

unread,
Nov 28, 2011, 3:31:26 PM11/28/11
to golang-nuts
I need some guidance on how to allocate/reserve a big chunk of file
extent.

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.

Jan Mercl

unread,
Nov 28, 2011, 4:44:14 PM11/28/11
to golan...@googlegroups.com

Chris Lu

unread,
Nov 28, 2011, 6:20:17 PM11/28/11
to golang-nuts
Jan, Thanks a lot! This is what I need!

Truncate... hmm, strange naming. I know it's legacy. Anyway, as long
as it works. Thanks!

Chris

Chris Wedgwood

unread,
Nov 28, 2011, 11:18:43 PM11/28/11
to Chris Lu, golang-nuts

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)

ChrisLu

unread,
Nov 29, 2011, 1:11:16 AM11/29/11
to golang-nuts
What I am working on is Go-version of Facebook's Haystack, to-be open
sourced. BTW: Go seems quite simple and robust for this kind of
backend systems.

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

Dave Cheney

unread,
Nov 29, 2011, 2:09:05 AM11/29/11
to ChrisLu, golang-nuts
Why not just open the file, write zeros to it and close it? 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.

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

Johann Höchtl

unread,
Nov 29, 2011, 3:36:26 AM11/29/11
to golan...@googlegroups.com, ChrisLu
Open the file and write zeros to it doesn't either guarantee the file to be unfragmented. As there is no standard fs call to prevent this, I think you will need to dig into ioctls to set specficy parameters for a file descriptor which are not exposed in any standard way.

Chris Wedgwood

unread,
Nov 29, 2011, 2:51:35 AM11/29/11
to Dave Cheney, ChrisLu, golang-nuts
> Why not just open the file, write zeros to it and close it?

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)

Chris Wedgwood

unread,
Nov 29, 2011, 1:34:44 PM11/29/11
to golan...@googlegroups.com, ChrisLu

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)

Albert Strasheim

unread,
Nov 30, 2011, 7:35:03 AM11/30/11
to golang-nuts
man 2 fallocate
Reply all
Reply to author
Forward
0 new messages