package bbolt

import (
	
	
	
	
	
	
	
	
	
	
)

// The largest step that can be taken when remapping the mmap.
const maxMmapStep = 1 << 30 // 1GB

// The data file format version.
const version = 2

// Represents a marker value to indicate that a file is a Bolt DB.
const magic uint32 = 0xED0CDAED

const pgidNoFreelist pgid = 0xffffffffffffffff

// IgnoreNoSync specifies whether the NoSync field of a DB is ignored when
// syncing changes to a file.  This is required as some operating systems,
// such as OpenBSD, do not have a unified buffer cache (UBC) and writes
// must be synchronized using the msync(2) syscall.
const IgnoreNoSync = runtime.GOOS == "openbsd"

// Default values if not set in a DB instance.
const (
	DefaultMaxBatchSize  int = 1000
	DefaultMaxBatchDelay     = 10 * time.Millisecond
	DefaultAllocSize         = 16 * 1024 * 1024
)

// default page size for db is set to the OS page size.
var defaultPageSize = os.Getpagesize()

// The time elapsed between consecutive file locking attempts.
const flockRetryTimeout = 50 * time.Millisecond

// FreelistType is the type of the freelist backend
type FreelistType string

const (
	// FreelistArrayType indicates backend freelist type is array
	FreelistArrayType = FreelistType("array")
	// FreelistMapType indicates backend freelist type is hashmap
	FreelistMapType = FreelistType("hashmap")
)

// DB represents a collection of buckets persisted to a file on disk.
// All data access is performed through transactions which can be obtained through the DB.
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
type DB struct {
	// When enabled, the database will perform a Check() after every commit.
	// A panic is issued if the database is in an inconsistent state. This
	// flag has a large performance impact so it should only be used for
	// debugging purposes.
	StrictMode bool

	// Setting the NoSync flag will cause the database to skip fsync()
	// calls after each commit. This can be useful when bulk loading data
	// into a database and you can restart the bulk load in the event of
	// a system failure or database corruption. Do not set this flag for
	// normal use.
	//
	// If the package global IgnoreNoSync constant is true, this value is
	// ignored.  See the comment on that constant for more details.
	//
	// THIS IS UNSAFE. PLEASE USE WITH CAUTION.
	NoSync bool

	// When true, skips syncing freelist to disk. This improves the database
	// write performance under normal operation, but requires a full database
	// re-sync during recovery.
	NoFreelistSync bool

	// FreelistType sets the backend freelist type. There are two options. Array which is simple but endures
	// dramatic performance degradation if database is large and framentation in freelist is common.
	// The alternative one is using hashmap, it is faster in almost all circumstances
	// but it doesn't guarantee that it offers the smallest page id available. In normal case it is safe.
	// The default type is array
	FreelistType FreelistType

	// When true, skips the truncate call when growing the database.
	// Setting this to true is only safe on non-ext3/ext4 systems.
	// Skipping truncation avoids preallocation of hard drive space and
	// bypasses a truncate() and fsync() syscall on remapping.
	//
	// https://github.com/boltdb/bolt/issues/284
	NoGrowSync bool

	// If you want to read the entire database fast, you can set MmapFlag to
	// syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead.
	MmapFlags int

	// MaxBatchSize is the maximum size of a batch. Default value is
	// copied from DefaultMaxBatchSize in Open.
	//
	// If <=0, disables batching.
	//
	// Do not change concurrently with calls to Batch.
	MaxBatchSize int

	// MaxBatchDelay is the maximum delay before a batch starts.
	// Default value is copied from DefaultMaxBatchDelay in Open.
	//
	// If <=0, effectively disables batching.
	//
	// Do not change concurrently with calls to Batch.
	MaxBatchDelay time.Duration

	// AllocSize is the amount of space allocated when the database
	// needs to create new pages. This is done to amortize the cost
	// of truncate() and fsync() when growing the data file.
	AllocSize int

	path     string
	openFile func(string, int, os.FileMode) (*os.File, error)
	file     *os.File
	dataref  []byte // mmap'ed readonly, write throws SEGV
	data     *[maxMapSize]byte
	datasz   int
	filesz   int // current on disk file size
	meta0    *meta
	meta1    *meta
	pageSize int
	opened   bool
	rwtx     *Tx
	txs      []*Tx
	stats    Stats

	freelist     *freelist
	freelistLoad sync.Once

	pagePool sync.Pool

	batchMu sync.Mutex
	batch   *batch

	rwlock   sync.Mutex   // Allows only one writer at a time.
	metalock sync.Mutex   // Protects meta page access.
	mmaplock sync.RWMutex // Protects mmap access during remapping.
	statlock sync.RWMutex // Protects stats access.

	ops struct {
		writeAt func(b []byte, off int64) (n int, err error)
	}

	// Read only mode.
	// When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately.
	readOnly bool
}

// Path returns the path to currently open database file.
func ( *DB) () string {
	return .path
}

// GoString returns the Go string representation of the database.
func ( *DB) () string {
	return fmt.Sprintf("bolt.DB{path:%q}", .path)
}

// String returns the string representation of the database.
func ( *DB) () string {
	return fmt.Sprintf("DB<%q>", .path)
}

// Open creates and opens a database at the given path.
// If the file does not exist then it will be created automatically.
// Passing in nil options will cause Bolt to open the database with the default options.
func ( string,  os.FileMode,  *Options) (*DB, error) {
	 := &DB{
		opened: true,
	}
	// Set default options if no options are provided.
	if  == nil {
		 = DefaultOptions
	}
	.NoSync = .NoSync
	.NoGrowSync = .NoGrowSync
	.MmapFlags = .MmapFlags
	.NoFreelistSync = .NoFreelistSync
	.FreelistType = .FreelistType

	// Set default values for later DB operations.
	.MaxBatchSize = DefaultMaxBatchSize
	.MaxBatchDelay = DefaultMaxBatchDelay
	.AllocSize = DefaultAllocSize

	 := os.O_RDWR
	if .ReadOnly {
		 = os.O_RDONLY
		.readOnly = true
	}

	.openFile = .OpenFile
	if .openFile == nil {
		.openFile = os.OpenFile
	}

	// Open data file and separate sync handler for metadata writes.
	var  error
	if .file,  = .openFile(, |os.O_CREATE, );  != nil {
		_ = .close()
		return nil, 
	}
	.path = .file.Name()

	// Lock file so that other processes using Bolt in read-write mode cannot
	// use the database  at the same time. This would cause corruption since
	// the two processes would write meta pages and free pages separately.
	// The database file is locked exclusively (only one process can grab the lock)
	// if !options.ReadOnly.
	// The database file is locked using the shared lock (more than one process may
	// hold a lock at the same time) otherwise (options.ReadOnly is set).
	if  := flock(, !.readOnly, .Timeout);  != nil {
		_ = .close()
		return nil, 
	}

	// Default values for test hooks
	.ops.writeAt = .file.WriteAt

	if .pageSize = .PageSize; .pageSize == 0 {
		// Set the default page size to the OS page size.
		.pageSize = defaultPageSize
	}

	// Initialize the database if it doesn't exist.
	if ,  := .file.Stat();  != nil {
		_ = .close()
		return nil, 
	} else if .Size() == 0 {
		// Initialize new files with meta pages.
		if  := .init();  != nil {
			// clean up file descriptor on initialization fail
			_ = .close()
			return nil, 
		}
	} else {
		// Read the first meta page to determine the page size.
		var  [0x1000]byte
		// If we can't read the page size, but can read a page, assume
		// it's the same as the OS or one given -- since that's how the
		// page size was chosen in the first place.
		//
		// If the first page is invalid and this OS uses a different
		// page size than what the database was created with then we
		// are out of luck and cannot access the database.
		//
		// TODO: scan for next page
		if ,  := .file.ReadAt([:], 0);  == nil &&  == len() {
			if  := .pageInBuffer([:], 0).meta(); .validate() == nil {
				.pageSize = int(.pageSize)
			}
		} else {
			_ = .close()
			return nil, ErrInvalid
		}
	}

	// Initialize page pool.
	.pagePool = sync.Pool{
		New: func() interface{} {
			return make([]byte, .pageSize)
		},
	}

	// Memory map the data file.
	if  := .mmap(.InitialMmapSize);  != nil {
		_ = .close()
		return nil, 
	}

	if .readOnly {
		return , nil
	}

	.loadFreelist()

	// Flush freelist when transitioning from no sync to sync so
	// NoFreelistSync unaware boltdb can open the db later.
	if !.NoFreelistSync && !.hasSyncedFreelist() {
		,  := .Begin(true)
		if  != nil {
			 = .Commit()
		}
		if  != nil {
			_ = .close()
			return nil, 
		}
	}

	// Mark the database as opened and return.
	return , nil
}

// loadFreelist reads the freelist if it is synced, or reconstructs it
// by scanning the DB if it is not synced. It assumes there are no
// concurrent accesses being made to the freelist.
func ( *DB) () {
	.freelistLoad.Do(func() {
		.freelist = newFreelist(.FreelistType)
		if !.hasSyncedFreelist() {
			// Reconstruct free list by scanning the DB.
			.freelist.readIDs(.freepages())
		} else {
			// Read free list from freelist page.
			.freelist.read(.page(.meta().freelist))
		}
		.stats.FreePageN = .freelist.free_count()
	})
}

func ( *DB) () bool {
	return .meta().freelist != pgidNoFreelist
}

// mmap opens the underlying memory-mapped file and initializes the meta references.
// minsz is the minimum size that the new mmap can be.
func ( *DB) ( int) error {
	.mmaplock.Lock()
	defer .mmaplock.Unlock()

	,  := .file.Stat()
	if  != nil {
		return fmt.Errorf("mmap stat error: %s", )
	} else if int(.Size()) < .pageSize*2 {
		return fmt.Errorf("file size too small")
	}

	// Ensure the size is at least the minimum size.
	var  = int(.Size())
	if  <  {
		 = 
	}
	,  = .mmapSize()
	if  != nil {
		return 
	}

	// Dereference all mmap references before unmapping.
	if .rwtx != nil {
		.rwtx.root.dereference()
	}

	// Unmap existing data before continuing.
	if  := .munmap();  != nil {
		return 
	}

	// Memory-map the data file as a byte slice.
	if  := mmap(, );  != nil {
		return 
	}

	// Save references to the meta pages.
	.meta0 = .page(0).meta()
	.meta1 = .page(1).meta()

	// Validate the meta pages. We only return an error if both meta pages fail
	// validation, since meta0 failing validation means that it wasn't saved
	// properly -- but we can recover using meta1. And vice-versa.
	 := .meta0.validate()
	 := .meta1.validate()
	if  != nil &&  != nil {
		return 
	}

	return nil
}

// munmap unmaps the data file from memory.
func ( *DB) () error {
	if  := munmap();  != nil {
		return fmt.Errorf("unmap error: " + .Error())
	}
	return nil
}

// mmapSize determines the appropriate size for the mmap given the current size
// of the database. The minimum size is 32KB and doubles until it reaches 1GB.
// Returns an error if the new mmap size is greater than the max allowed.
func ( *DB) ( int) (int, error) {
	// Double the size from 32KB until 1GB.
	for  := uint(15);  <= 30; ++ {
		if  <= 1<< {
			return 1 << , nil
		}
	}

	// Verify the requested size is not above the maximum allowed.
	if  > maxMapSize {
		return 0, fmt.Errorf("mmap too large")
	}

	// If larger than 1GB then grow by 1GB at a time.
	 := int64()
	if  :=  % int64(maxMmapStep);  > 0 {
		 += int64(maxMmapStep) - 
	}

	// Ensure that the mmap size is a multiple of the page size.
	// This should always be true since we're incrementing in MBs.
	 := int64(.pageSize)
	if ( % ) != 0 {
		 = (( / ) + 1) * 
	}

	// If we've exceeded the max size then only grow up to the max size.
	if  > maxMapSize {
		 = maxMapSize
	}

	return int(), nil
}

// init creates a new database file and initializes its meta pages.
func ( *DB) () error {
	// Create two meta pages on a buffer.
	 := make([]byte, .pageSize*4)
	for  := 0;  < 2; ++ {
		 := .pageInBuffer([:], pgid())
		.id = pgid()
		.flags = metaPageFlag

		// Initialize the meta page.
		 := .meta()
		.magic = magic
		.version = version
		.pageSize = uint32(.pageSize)
		.freelist = 2
		.root = bucket{root: 3}
		.pgid = 4
		.txid = txid()
		.checksum = .sum64()
	}

	// Write an empty freelist at page 3.
	 := .pageInBuffer([:], pgid(2))
	.id = pgid(2)
	.flags = freelistPageFlag
	.count = 0

	// Write an empty leaf page at page 4.
	 = .pageInBuffer([:], pgid(3))
	.id = pgid(3)
	.flags = leafPageFlag
	.count = 0

	// Write the buffer to our data file.
	if ,  := .ops.writeAt(, 0);  != nil {
		return 
	}
	if  := fdatasync();  != nil {
		return 
	}

	return nil
}

// Close releases all database resources.
// It will block waiting for any open transactions to finish
// before closing the database and returning.
func ( *DB) () error {
	.rwlock.Lock()
	defer .rwlock.Unlock()

	.metalock.Lock()
	defer .metalock.Unlock()

	.mmaplock.Lock()
	defer .mmaplock.Unlock()

	return .close()
}

func ( *DB) () error {
	if !.opened {
		return nil
	}

	.opened = false

	.freelist = nil

	// Clear ops.
	.ops.writeAt = nil

	// Close the mmap.
	if  := .munmap();  != nil {
		return 
	}

	// Close file handles.
	if .file != nil {
		// No need to unlock read-only file.
		if !.readOnly {
			// Unlock the file.
			if  := funlock();  != nil {
				log.Printf("bolt.Close(): funlock error: %s", )
			}
		}

		// Close the file descriptor.
		if  := .file.Close();  != nil {
			return fmt.Errorf("db file close: %s", )
		}
		.file = nil
	}

	.path = ""
	return nil
}

// Begin starts a new transaction.
// Multiple read-only transactions can be used concurrently but only one
// write transaction can be used at a time. Starting multiple write transactions
// will cause the calls to block and be serialized until the current write
// transaction finishes.
//
// Transactions should not be dependent on one another. Opening a read
// transaction and a write transaction in the same goroutine can cause the
// writer to deadlock because the database periodically needs to re-mmap itself
// as it grows and it cannot do that while a read transaction is open.
//
// If a long running read transaction (for example, a snapshot transaction) is
// needed, you might want to set DB.InitialMmapSize to a large enough value
// to avoid potential blocking of write transaction.
//
// IMPORTANT: You must close read-only transactions after you are finished or
// else the database will not reclaim old pages.
func ( *DB) ( bool) (*Tx, error) {
	if  {
		return .beginRWTx()
	}
	return .beginTx()
}

func ( *DB) () (*Tx, error) {
	// Lock the meta pages while we initialize the transaction. We obtain
	// the meta lock before the mmap lock because that's the order that the
	// write transaction will obtain them.
	.metalock.Lock()

	// Obtain a read-only lock on the mmap. When the mmap is remapped it will
	// obtain a write lock so all transactions must finish before it can be
	// remapped.
	.mmaplock.RLock()

	// Exit if the database is not open yet.
	if !.opened {
		.mmaplock.RUnlock()
		.metalock.Unlock()
		return nil, ErrDatabaseNotOpen
	}

	// Create a transaction associated with the database.
	 := &Tx{}
	.init()

	// Keep track of transaction until it closes.
	.txs = append(.txs, )
	 := len(.txs)

	// Unlock the meta pages.
	.metalock.Unlock()

	// Update the transaction stats.
	.statlock.Lock()
	.stats.TxN++
	.stats.OpenTxN = 
	.statlock.Unlock()

	return , nil
}

func ( *DB) () (*Tx, error) {
	// If the database was opened with Options.ReadOnly, return an error.
	if .readOnly {
		return nil, ErrDatabaseReadOnly
	}

	// Obtain writer lock. This is released by the transaction when it closes.
	// This enforces only one writer transaction at a time.
	.rwlock.Lock()

	// Once we have the writer lock then we can lock the meta pages so that
	// we can set up the transaction.
	.metalock.Lock()
	defer .metalock.Unlock()

	// Exit if the database is not open yet.
	if !.opened {
		.rwlock.Unlock()
		return nil, ErrDatabaseNotOpen
	}

	// Create a transaction associated with the database.
	 := &Tx{writable: true}
	.init()
	.rwtx = 
	.freePages()
	return , nil
}

// freePages releases any pages associated with closed read-only transactions.
func ( *DB) () {
	// Free all pending pages prior to earliest open transaction.
	sort.Sort(txsById(.txs))
	 := txid(0xFFFFFFFFFFFFFFFF)
	if len(.txs) > 0 {
		 = .txs[0].meta.txid
	}
	if  > 0 {
		.freelist.release( - 1)
	}
	// Release unused txid extents.
	for ,  := range .txs {
		.freelist.releaseRange(, .meta.txid-1)
		 = .meta.txid + 1
	}
	.freelist.releaseRange(, txid(0xFFFFFFFFFFFFFFFF))
	// Any page both allocated and freed in an extent is safe to release.
}

type txsById []*Tx

func ( txsById) () int           { return len() }
func ( txsById) (,  int)      { [], [] = [], [] }
func ( txsById) (,  int) bool { return [].meta.txid < [].meta.txid }

// removeTx removes a transaction from the database.
func ( *DB) ( *Tx) {
	// Release the read lock on the mmap.
	.mmaplock.RUnlock()

	// Use the meta lock to restrict access to the DB object.
	.metalock.Lock()

	// Remove the transaction.
	for ,  := range .txs {
		if  ==  {
			 := len(.txs) - 1
			.txs[] = .txs[]
			.txs[] = nil
			.txs = .txs[:]
			break
		}
	}
	 := len(.txs)

	// Unlock the meta pages.
	.metalock.Unlock()

	// Merge statistics.
	.statlock.Lock()
	.stats.OpenTxN = 
	.stats.TxStats.add(&.stats)
	.statlock.Unlock()
}

// Update executes a function within the context of a read-write managed transaction.
// If no error is returned from the function then the transaction is committed.
// If an error is returned then the entire transaction is rolled back.
// Any error that is returned from the function or returned from the commit is
// returned from the Update() method.
//
// Attempting to manually commit or rollback within the function will cause a panic.
func ( *DB) ( func(*Tx) error) error {
	,  := .Begin(true)
	if  != nil {
		return 
	}

	// Make sure the transaction rolls back in the event of a panic.
	defer func() {
		if .db != nil {
			.rollback()
		}
	}()

	// Mark as a managed tx so that the inner function cannot manually commit.
	.managed = true

	// If an error is returned from the function then rollback and return error.
	 = ()
	.managed = false
	if  != nil {
		_ = .Rollback()
		return 
	}

	return .Commit()
}

// View executes a function within the context of a managed read-only transaction.
// Any error that is returned from the function is returned from the View() method.
//
// Attempting to manually rollback within the function will cause a panic.
func ( *DB) ( func(*Tx) error) error {
	,  := .Begin(false)
	if  != nil {
		return 
	}

	// Make sure the transaction rolls back in the event of a panic.
	defer func() {
		if .db != nil {
			.rollback()
		}
	}()

	// Mark as a managed tx so that the inner function cannot manually rollback.
	.managed = true

	// If an error is returned from the function then pass it through.
	 = ()
	.managed = false
	if  != nil {
		_ = .Rollback()
		return 
	}

	return .Rollback()
}

// Batch calls fn as part of a batch. It behaves similar to Update,
// except:
//
// 1. concurrent Batch calls can be combined into a single Bolt
// transaction.
//
// 2. the function passed to Batch may be called multiple times,
// regardless of whether it returns error or not.
//
// This means that Batch function side effects must be idempotent and
// take permanent effect only after a successful return is seen in
// caller.
//
// The maximum batch size and delay can be adjusted with DB.MaxBatchSize
// and DB.MaxBatchDelay, respectively.
//
// Batch is only useful when there are multiple goroutines calling it.
func ( *DB) ( func(*Tx) error) error {
	 := make(chan error, 1)

	.batchMu.Lock()
	if (.batch == nil) || (.batch != nil && len(.batch.calls) >= .MaxBatchSize) {
		// There is no existing batch, or the existing batch is full; start a new one.
		.batch = &batch{
			db: ,
		}
		.batch.timer = time.AfterFunc(.MaxBatchDelay, .batch.trigger)
	}
	.batch.calls = append(.batch.calls, call{fn: , err: })
	if len(.batch.calls) >= .MaxBatchSize {
		// wake up batch, it's ready to run
		go .batch.trigger()
	}
	.batchMu.Unlock()

	 := <-
	if  == trySolo {
		 = .Update()
	}
	return 
}

type call struct {
	fn  func(*Tx) error
	err chan<- error
}

type batch struct {
	db    *DB
	timer *time.Timer
	start sync.Once
	calls []call
}

// trigger runs the batch if it hasn't already been run.
func ( *batch) () {
	.start.Do(.run)
}

// run performs the transactions in the batch and communicates results
// back to DB.Batch.
func ( *batch) () {
	.db.batchMu.Lock()
	.timer.Stop()
	// Make sure no new work is added to this batch, but don't break
	// other batches.
	if .db.batch ==  {
		.db.batch = nil
	}
	.db.batchMu.Unlock()

:
	for len(.calls) > 0 {
		var  = -1
		 := .db.Update(func( *Tx) error {
			for ,  := range .calls {
				if  := safelyCall(.fn, );  != nil {
					 = 
					return 
				}
			}
			return nil
		})

		if  >= 0 {
			// take the failing transaction out of the batch. it's
			// safe to shorten b.calls here because db.batch no longer
			// points to us, and we hold the mutex anyway.
			 := .calls[]
			.calls[], .calls = .calls[len(.calls)-1], .calls[:len(.calls)-1]
			// tell the submitter re-run it solo, continue with the rest of the batch
			.err <- trySolo
			continue 
		}

		// pass success, or bolt internal errors, to all callers
		for ,  := range .calls {
			.err <- 
		}
		break 
	}
}

// trySolo is a special sentinel error value used for signaling that a
// transaction function should be re-run. It should never be seen by
// callers.
var trySolo = errors.New("batch function returned an error and should be re-run solo")

type panicked struct {
	reason interface{}
}

func ( panicked) () string {
	if ,  := .reason.(error);  {
		return .Error()
	}
	return fmt.Sprintf("panic: %v", .reason)
}

func ( func(*Tx) error,  *Tx) ( error) {
	defer func() {
		if  := recover();  != nil {
			 = panicked{}
		}
	}()
	return ()
}

// Sync executes fdatasync() against the database file handle.
//
// This is not necessary under normal operation, however, if you use NoSync
// then it allows you to force the database file to sync against the disk.
func ( *DB) () error { return fdatasync() }

// Stats retrieves ongoing performance stats for the database.
// This is only updated when a transaction closes.
func ( *DB) () Stats {
	.statlock.RLock()
	defer .statlock.RUnlock()
	return .stats
}

// This is for internal access to the raw data bytes from the C cursor, use
// carefully, or not at all.
func ( *DB) () *Info {
	return &Info{uintptr(unsafe.Pointer(&.data[0])), .pageSize}
}

// page retrieves a page reference from the mmap based on the current page size.
func ( *DB) ( pgid) *page {
	 :=  * pgid(.pageSize)
	return (*page)(unsafe.Pointer(&.data[]))
}

// pageInBuffer retrieves a page reference from a given byte array based on the current page size.
func ( *DB) ( []byte,  pgid) *page {
	return (*page)(unsafe.Pointer(&[*pgid(.pageSize)]))
}

// meta retrieves the current meta page reference.
func ( *DB) () *meta {
	// We have to return the meta with the highest txid which doesn't fail
	// validation. Otherwise, we can cause errors when in fact the database is
	// in a consistent state. metaA is the one with the higher txid.
	 := .meta0
	 := .meta1
	if .meta1.txid > .meta0.txid {
		 = .meta1
		 = .meta0
	}

	// Use higher meta page if valid. Otherwise fallback to previous, if valid.
	if  := .validate();  == nil {
		return 
	} else if  := .validate();  == nil {
		return 
	}

	// This should never be reached, because both meta1 and meta0 were validated
	// on mmap() and we do fsync() on every write.
	panic("bolt.DB.meta(): invalid meta pages")
}

// allocate returns a contiguous block of memory starting at a given page.
func ( *DB) ( txid,  int) (*page, error) {
	// Allocate a temporary buffer for the page.
	var  []byte
	if  == 1 {
		 = .pagePool.Get().([]byte)
	} else {
		 = make([]byte, *.pageSize)
	}
	 := (*page)(unsafe.Pointer(&[0]))
	.overflow = uint32( - 1)

	// Use pages from the freelist if they are available.
	if .id = .freelist.allocate(, ); .id != 0 {
		return , nil
	}

	// Resize mmap() if we're at the end.
	.id = .rwtx.meta.pgid
	var  = int((.id+pgid())+1) * .pageSize
	if  >= .datasz {
		if  := .mmap();  != nil {
			return nil, fmt.Errorf("mmap allocate error: %s", )
		}
	}

	// Move the page id high water mark.
	.rwtx.meta.pgid += pgid()

	return , nil
}

// grow grows the size of the database to the given sz.
func ( *DB) ( int) error {
	// Ignore if the new size is less than available file size.
	if  <= .filesz {
		return nil
	}

	// If the data is smaller than the alloc size then only allocate what's needed.
	// Once it goes over the allocation size then allocate in chunks.
	if .datasz < .AllocSize {
		 = .datasz
	} else {
		 += .AllocSize
	}

	// Truncate and fsync to ensure file size metadata is flushed.
	// https://github.com/boltdb/bolt/issues/284
	if !.NoGrowSync && !.readOnly {
		if runtime.GOOS != "windows" {
			if  := .file.Truncate(int64());  != nil {
				return fmt.Errorf("file resize error: %s", )
			}
		}
		if  := .file.Sync();  != nil {
			return fmt.Errorf("file sync error: %s", )
		}
	}

	.filesz = 
	return nil
}

func ( *DB) () bool {
	return .readOnly
}

func ( *DB) () []pgid {
	,  := .beginTx()
	defer func() {
		 = .Rollback()
		if  != nil {
			panic("freepages: failed to rollback tx")
		}
	}()
	if  != nil {
		panic("freepages: failed to open read only tx")
	}

	 := make(map[pgid]*page)
	 := make(map[pgid]bool)
	 := make(chan error)
	go func() {
		for  := range  {
			panic(fmt.Sprintf("freepages: failed to get all reachable pages (%v)", ))
		}
	}()
	.checkBucket(&.root, , , )
	close()

	var  []pgid
	for  := pgid(2);  < .meta().pgid; ++ {
		if ,  := []; ! {
			 = append(, )
		}
	}
	return 
}

// Options represents the options that can be set when opening a database.
type Options struct {
	// Timeout is the amount of time to wait to obtain a file lock.
	// When set to zero it will wait indefinitely. This option is only
	// available on Darwin and Linux.
	Timeout time.Duration

	// Sets the DB.NoGrowSync flag before memory mapping the file.
	NoGrowSync bool

	// Do not sync freelist to disk. This improves the database write performance
	// under normal operation, but requires a full database re-sync during recovery.
	NoFreelistSync bool

	// FreelistType sets the backend freelist type. There are two options. Array which is simple but endures
	// dramatic performance degradation if database is large and framentation in freelist is common.
	// The alternative one is using hashmap, it is faster in almost all circumstances
	// but it doesn't guarantee that it offers the smallest page id available. In normal case it is safe.
	// The default type is array
	FreelistType FreelistType

	// Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to
	// grab a shared lock (UNIX).
	ReadOnly bool

	// Sets the DB.MmapFlags flag before memory mapping the file.
	MmapFlags int

	// InitialMmapSize is the initial mmap size of the database
	// in bytes. Read transactions won't block write transaction
	// if the InitialMmapSize is large enough to hold database mmap
	// size. (See DB.Begin for more information)
	//
	// If <=0, the initial map size is 0.
	// If initialMmapSize is smaller than the previous database size,
	// it takes no effect.
	InitialMmapSize int

	// PageSize overrides the default OS page size.
	PageSize int

	// NoSync sets the initial value of DB.NoSync. Normally this can just be
	// set directly on the DB itself when returned from Open(), but this option
	// is useful in APIs which expose Options but not the underlying DB.
	NoSync bool

	// OpenFile is used to open files. It defaults to os.OpenFile. This option
	// is useful for writing hermetic tests.
	OpenFile func(string, int, os.FileMode) (*os.File, error)
}

// DefaultOptions represent the options used if nil options are passed into Open().
// No timeout is used which will cause Bolt to wait indefinitely for a lock.
var DefaultOptions = &Options{
	Timeout:      0,
	NoGrowSync:   false,
	FreelistType: FreelistArrayType,
}

// Stats represents statistics about the database.
type Stats struct {
	// Freelist stats
	FreePageN     int // total number of free pages on the freelist
	PendingPageN  int // total number of pending pages on the freelist
	FreeAlloc     int // total bytes allocated in free pages
	FreelistInuse int // total bytes used by the freelist

	// Transaction stats
	TxN     int // total number of started read transactions
	OpenTxN int // number of currently open read transactions

	TxStats TxStats // global, ongoing stats.
}

// Sub calculates and returns the difference between two sets of database stats.
// This is useful when obtaining stats at two different points and time and
// you need the performance counters that occurred within that time span.
func ( *Stats) ( *Stats) Stats {
	if  == nil {
		return *
	}
	var  Stats
	.FreePageN = .FreePageN
	.PendingPageN = .PendingPageN
	.FreeAlloc = .FreeAlloc
	.FreelistInuse = .FreelistInuse
	.TxN = .TxN - .TxN
	.TxStats = .TxStats.Sub(&.TxStats)
	return 
}

type Info struct {
	Data     uintptr
	PageSize int
}

type meta struct {
	magic    uint32
	version  uint32
	pageSize uint32
	flags    uint32
	root     bucket
	freelist pgid
	pgid     pgid
	txid     txid
	checksum uint64
}

// validate checks the marker bytes and version of the meta page to ensure it matches this binary.
func ( *meta) () error {
	if .magic != magic {
		return ErrInvalid
	} else if .version != version {
		return ErrVersionMismatch
	} else if .checksum != 0 && .checksum != .sum64() {
		return ErrChecksum
	}
	return nil
}

// copy copies one meta object to another.
func ( *meta) ( *meta) {
	* = *
}

// write writes the meta onto a page.
func ( *meta) ( *page) {
	if .root.root >= .pgid {
		panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", .root.root, .pgid))
	} else if .freelist >= .pgid && .freelist != pgidNoFreelist {
		// TODO: reject pgidNoFreeList if !NoFreelistSync
		panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", .freelist, .pgid))
	}

	// Page id is either going to be 0 or 1 which we can determine by the transaction ID.
	.id = pgid(.txid % 2)
	.flags |= metaPageFlag

	// Calculate the checksum.
	.checksum = .sum64()

	.copy(.meta())
}

// generates the checksum for the meta.
func ( *meta) () uint64 {
	var  = fnv.New64a()
	_, _ = .Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer())[:])
	return .Sum64()
}

// _assert will panic with a given formatted message if the given condition is false.
func ( bool,  string,  ...interface{}) {
	if ! {
		panic(fmt.Sprintf("assertion failed: "+, ...))
	}
}