V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
BBCCBB
V2EX  ›  程序员

求指教 boltdb 中 关于文件 grow 和 remmap 的逻辑

  •  
  •   BBCCBB · 175 天前 · 621 次点击
    这是一个创建于 175 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://github.com/etcd-io/bbolt/blob/master/tx.go#L141 tx.Commit()方法中, 当重新写 freelist 时 tx.meta.pgid 有变动,就调用 grow,这个优化怎么理解呢? 完全 get 不到它的点,

    commitFreelist 里调用 grow 方法时, 非 windows 系统 需要先调用 ftruncate, 再用 fsync.

    func (db *DB) grow(sz int) error {
    	// Ignore if the new size is less than available file size.
    	if sz <= db.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 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)
    		}
    		if db.Mlock {
    			// unlock old file and lock new one
    			if err := db.mrelock(db.filesz, sz); err != nil {
    				return fmt.Errorf("mlock/munlock error: %s", err)
    			}
    		}
    	}
    
    	db.filesz = sz
    	return nil
    }
    

    但在 mmap()方法里, windows 先调用了 ftruncate, 再调用 fsync, unix 这里只有 mmap. 这又是什么操作?

    // windows
    func mmap(db *DB, sz int) error {
    	if !db.readOnly {
    		// Truncate the database to the size of the mmap.
    		if err := db.file.Truncate(int64(sz)); err != nil {
    			return fmt.Errorf("truncate: %s", err)
    		}
    	}
    
    	// Open a file mapping handle.
    	sizelo := uint32(sz >> 32)
    	sizehi := uint32(sz) & 0xffffffff
    	h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
    	if h == 0 {
    		return os.NewSyscallError("CreateFileMapping", errno)
    	}
    
    	// Create the memory map.
    	addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz))
    	if addr == 0 {
    		return os.NewSyscallError("MapViewOfFile", errno)
    	}
    
    	// Close mapping handle.
    	if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
    		return os.NewSyscallError("CloseHandle", err)
    	}
    
    	// Convert to a byte array.
    	db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
    	db.datasz = sz
    
    	return nil
    }
    
    // unix
    // mmap memory maps a DB's data file.
    func mmap(db *DB, sz int) error {
    	// Map the data file to memory.
    	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
    	if err != nil {
    		return err
    	}
    
    	// Advise the kernel that the mmap is accessed randomly.
    	err = unix.Madvise(b, syscall.MADV_RANDOM)
    	if err != nil && err != syscall.ENOSYS {
    		// Ignore not implemented error in kernel because it still works.
    		return fmt.Errorf("madvise: %s", err)
    	}
    
    	// Save the original byte slice and convert to a byte array pointer.
    	db.dataref = b
    	db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
    	db.datasz = sz
    	return nil
    }
    
    BBCCBB
        1
    BBCCBB  
    OP
       175 天前
    BBCCBB
        2
    BBCCBB  
    OP
       174 天前
    BBCCBB
        3
    BBCCBB  
    OP
       174 天前
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1062 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 22:27 · PVG 06:27 · LAX 15:27 · JFK 18:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.