第七节 db.allocate()和db.grow()分析

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

    // Use pages from the freelist if they are available.
    // 先从空闲列表中找
    if p.id = db.freelist.allocate(count); p.id != 0 {
        return p, nil
    }

    // 找不到的话,就按照事务的pgid来分配
    // 表示需要从文件内部扩大

    // Resize mmap() if we're at the end.
    p.id = db.rwtx.meta.pgid
    // 因此需要判断是否目前所有的页数已经大于了mmap映射出来的空间
    // 这儿计算的页面总数是从当前的id后还要计算count+1个
    var minsz = int((p.id+pgid(count))+1) * db.pageSize
    if minsz >= db.datasz {
        if err := db.mmap(minsz); err != nil {
            return nil, fmt.Errorf("mmap allocate error: %s", err)
        }
    }

    // Move the page id high water mark.
    // 如果不是从freelist中找到的空间的话,更新meta的id,也就意味着是从文件中新扩展的页
    db.rwtx.meta.pgid += pgid(count)

    return p, nil
}

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

    // 满足这个条件sz>filesz

    // 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 db.datasz < db.AllocSize {
        sz = db.datasz
    } else {
        sz += db.AllocSize
    }

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

    db.filesz = sz
    return nil
}

results matching ""

    No results matching ""