func (m *MFile) GetBlock(n uint64) []byte {
	offset := n * m.blkSize
	if offset >= m.size {
		return nil
	}
	return m.mmap[offset : offset+m.blkSize]
}
GetBlock returns the n-th block as a byte slice, including any trailing zero padding.
The returned bytes are from the underlying mmap'd buffer and will be invalid after a call to Close().
package storage
import (
	"errors"
	"fmt"
	"os"
	"github.com/barakmich/mmap-go"
)
type MFile struct {
	mmap    mmap.MMap
	blkSize uint64
	size    uint64
}
func CreateOrOpenMFile(path string, size uint64, blkSize uint64) (*MFile, error) {
	finfo, err := os.Stat(path)
	if os.IsNotExist(err) {
		err := CreateMFile(path, size)
		if err != nil {
			return nil, err
		}
	}
	if finfo != nil && finfo.Size() != int64(size) {
		if finfo.Size() > int64(size) {
			return nil, fmt.Errorf("Specified size %d is smaller than current size %d.", size, finfo.Size())
		}
		clog.Debugf("mfile: expand %s %d to %d", path, finfo.Size(), size)
		os.Truncate(path, int64(size))
	}
	return OpenMFile(path, blkSize)
}
func CreateMFile(path string, size uint64) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return f.Truncate(int64(size))
}
func OpenMFile(path string, blkSize uint64) (*MFile, error) {
	var mf MFile
	f, err := os.OpenFile(path, os.O_RDWR, 0644)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	st, err := f.Stat()
	if err != nil {
		return nil, err
	}
	mf.size = uint64(st.Size())
	if mf.size%blkSize != 0 {
		return nil, fmt.Errorf("File size is not a multiple of the block size: %d size, %d blksize", mf.size, blkSize)
	}
	mf.mmap, err = mmap.Map(f, mmap.RDWR, 0)
	if err != nil {
		return nil, err
	}
	mf.blkSize = blkSize
	return &mf, nil
}