in file.go [503:593]
func initNewFile(file vfs.File, opts Options) reason {
const op = "txfile/create"
var flags uint32
if opts.MaxSize > 0 && opts.Prealloc {
flags |= metaFlagPrealloc
if err := file.Truncate(int64(opts.MaxSize)); err != nil {
return fileErrWrap(op, file.Name(), err).of(FileCreationFailed).
report("unable to preallocate file")
}
}
maxSize := opts.MaxSize
if opts.Flags.check(FlagUnboundMaxSize) {
maxSize = 0
}
pageSize := opts.PageSize
if opts.PageSize == 0 {
pageSize = uint32(os.Getpagesize())
if pageSize < minPageSize {
pageSize = minPageSize
}
}
if !isPowerOf2(uint64(pageSize)) {
cause := raiseInvalidParamf("pageSize %v is not power of 2", pageSize)
return fileErrWrap(op, file.Name(), cause).of(FileCreationFailed)
}
if pageSize < minPageSize {
cause := raiseInvalidParamf("pageSize must be >= %v", minPageSize)
return fileErrWrap(op, file.Name(), cause).of(FileCreationFailed)
}
// create buffer to hold contents for the initial pages:
// 1. meta page 0
// 2. meta page 1
// 3. free list page (only of opts.InitMetaArea > 0)
buf := make([]byte, pageSize*3)
// create freelist with meta area only and pre-compute page IDs
requiredPages := 2
metaTotal := opts.InitMetaArea
dataEndMarker := PageID(2)
metaEndMarker := PageID(0) // no meta area
freelistPage := PageID(0)
if metaTotal > 0 {
requiredPages = 3
freelistPage = PageID(2)
// move pages from data area to new meta area by updating markers
dataEndMarker += PageID(metaTotal)
metaEndMarker = dataEndMarker
// write freelist, so to make meta page allocatable
hdr, body := castFreePage(buf[int(pageSize)*2:])
hdr.next.Set(0)
if metaTotal > 1 {
hdr.count.Set(1)
encodeRegion(body, true, region{
id: freelistPage + 1,
count: metaTotal - 1,
})
}
}
// create meta pages
for i := 0; i < 2; i++ {
pg := castMetaPage(buf[int(pageSize)*i:])
pg.Init(flags, pageSize, maxSize)
pg.txid.Set(uint64(1 - i))
pg.dataEndMarker.Set(dataEndMarker) // endMarker is index of next to be allocated page at end of file
pg.metaEndMarker.Set(metaEndMarker)
pg.metaTotal.Set(uint64(metaTotal))
pg.freelist.Set(freelistPage)
pg.Finalize()
}
// write initial pages to disk
err := writeAt(op, file, buf[:int(pageSize)*requiredPages], 0)
if err == nil {
if syncErr := file.Sync(vfs.SyncAll); syncErr != nil {
err = fileErrWrap(op, file.Name(), syncErr)
}
}
if err != nil {
return fileErrWrap(op, file.Name(), err).of(FileCreationFailed).
report("io error while initializing data file")
}
return nil
}