func initNewFile()

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
}