func (b *Buffer) Unmap() {
	if err := syscall.Munmap(b.data); err != nil {
		panic(err)
	}
}
Unmap unmaps the buffer file from memory.
package buffer
import (
	"errors"
	"fmt"
	"os"
	"sync"
	"syscall"
	"github.com/ashishgandhi/buffer/binary"
)
const (
	size     = 4  
	sequence = 8  
	total    = size + sequence
	metadata = 4 << 10  
)
var maxBytes uint32 = (1 << (uint(size) * 8)) - total  
type frame []byte
var (
	errFrameTooBig = fmt.Errorf("buffer: data more than max %d bytes", maxBytes)
	errDataTooBig  = errors.New("buffer: data overflows buffer")
)
func newFrame(seq uint64, data []byte) (frame, error) {
	if len(data) > int(maxBytes) {
		return nil, errFrameTooBig
	}
	var f frame = make([]byte, len(data)+total)
	binary.PutLittleEndianUint32(f, 0, uint32(len(f)))
	binary.PutLittleEndianUint64(f, size, seq)
	copy(f[total:], data)
	return f, nil
}
func (f frame) size() uint32 {
	if len(f) < size {
		return 0
	}
	return binary.GetLittleEndianUint32(f, 0)
}
func (f frame) seq() uint64 {
	if len(f) < total {
		return 0
	}
	return binary.GetLittleEndianUint64(f, size)
}
func (f frame) data() []byte {
	if len(f) < total {
		return nil
	}
	return f[total:]
}
type Buffer struct {
	capacity uint64
	nextSeq  uint64
	biggest  uint32  
	length   uint64  
	first uint64
	last  uint64
	filename string
	data     []byte
	mu sync.RWMutex  
}
func New(capacity int, filename string) (*Buffer, error) {
	if _, err := os.Stat(filename); !os.IsNotExist(err) {
		return nil, ErrFileExists
	}
	f, err := os.Create(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	fsize := capacity + metadata
	if err := syscall.Truncate(filename, int64(fsize)); err != nil {
		return nil, err
	}
	data, err := syscall.Mmap(
		int(f.Fd()), 0, fsize,
		syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED,
	)
	if err != nil {
		return nil, err
	}
	b := &Buffer{
		capacity: uint64(capacity),  
		filename: f.Name(),
		data:     data,
	}
	b.updateMeta()
	return b, nil
}
func (b *Buffer) Len() uint64 {
	b.mu.RLock()
	defer b.mu.RUnlock()
	return b.length
}
func (b *Buffer) Remaining(from Cursor) uint64 {
	b.mu.RLock()
	defer b.mu.RUnlock()
	if from.offset > b.last {
		return 0
	}
	off := from.offset
	if off < b.first {
		off = b.first
	}
	remaining := b.last - off
	remaining += uint64(b.frameSize(b.last))
	return remaining
}
func (b *Buffer) updateMeta() {
	off := int(b.capacity)
	binary.PutLittleEndianUint64(b.data, off, b.first)
	binary.PutLittleEndianUint64(b.data, off+8, b.last)
	binary.PutLittleEndianUint64(b.data, off+16, b.nextSeq)
	binary.PutLittleEndianUint32(b.data, off+24, b.biggest)
	binary.PutLittleEndianUint64(b.data, off+28, b.length)
}
func Load(filename string) (*Buffer, error) {
	b := &Buffer{filename: filename}
	err := b.reload()
	return b, err
}
func (b *Buffer) reload() error {
	stat, err := os.Stat(b.filename)
	if err != nil {
		return err
	}
	fsize := uint64(stat.Size())
	b.capacity = fsize - metadata
	f, err := os.OpenFile(b.filename, os.O_RDWR, 0600)
	if err != nil {
		return err
	}
	data, err := syscall.Mmap(
		int(f.Fd()), 0, int(fsize),
		syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED,
	)
	if err != nil {
		return err
	}
	b.data = data
	off := int(b.capacity)
	b.first = binary.GetLittleEndianUint64(b.data, off)
	b.last = binary.GetLittleEndianUint64(b.data, off+8)
	b.nextSeq = binary.GetLittleEndianUint64(b.data, off+16)
	b.biggest = binary.GetLittleEndianUint32(b.data, off+24)
	b.length = binary.GetLittleEndianUint64(b.data, off+28)
	return nil
}
func (b *Buffer) Insert(data []byte) error {
	if len(data) == 0 {
		return nil
	}
	b.mu.Lock()
	defer b.mu.Unlock()
	frame, err := newFrame(b.nextSeq, data)  
	if err != nil {
		return err
	}
	fsize := frame.size()
	fsize64 := uint64(fsize)
	if fsize64 > b.capacity {
		return errDataTooBig
	}
	b.last = b.nextFrameOffset(b.last)  
	b.updateFirst(fsize64)
	start := b.last % b.capacity
	end := start + fsize64
	var wrap bool
	if end > b.capacity {
		wrap = true
		end = b.capacity
	}
	copyoff := end - start
	copy(b.data[start:end], frame[:copyoff])
	if wrap {
		copy(b.data, frame[copyoff:])
	}
	if fsize > b.biggest {
		b.biggest = fsize
	}
	b.nextSeq++
	b.length += uint64(len(data))
	b.updateMeta()
	return nil
}
func (b *Buffer) updateFirst(fsize uint64) {
	if b.biggest == 0 {
		return
	}
	var (
		start    = b.last % b.capacity
		end      = (start + fsize) % b.capacity
		wrapping = end <= start
	)
	if start == end {
		b.length = 0
		b.first = b.last
		return
	}
	for {
		if b.first == b.last {
			return
		}
		firstWrapped := b.first % b.capacity
		if wrapping {
			if end <= firstWrapped && firstWrapped < start {
				return
			}
		} else {
			if end <= firstWrapped {
				return
			}
			if start > firstWrapped {
				return
			}
		}
		second := b.nextFrameOffset(b.first)
		b.length -= (second - b.first - total)
		b.first = second
	}
}
func (b *Buffer) nextFrameOffset(offset uint64) uint64 {
	return offset + uint64(b.frameSize(offset))
}
func (b *Buffer) frame(offset uint64) frame {
	return b.frameOfLen(offset, b.frameSize(offset))
}
func (b *Buffer) frameSize(offset uint64) uint32 {
	f := b.frameOfLen(offset, size)
	return f.size()
}
func (b *Buffer) frameOfLen(offset uint64, length uint32) frame {
	if length > b.biggest {
		return nil
	}
	var f frame
	start := offset % b.capacity
	end := start + uint64(length)
	if end > b.capacity {
		f = make([]byte, length)
		copy(f, b.data[start:b.capacity])
		copy(f[b.capacity-start:], b.data[:end%b.capacity])
	} else {
		f = b.data[start:end]
	}
	return f
}
var (
	ErrFileExists  = errors.New("buffer: log file already exists")
	ErrPartialData = errors.New("buffer: partial data returned")
	ErrNotArrived  = errors.New("buffer: data has not yet arrived")
)
func (b *Buffer) Read(data []byte, c Cursor) (n int, next Cursor, err error) {
	b.mu.RLock()
	defer b.mu.RUnlock()
	seq, offset := c.seq, c.offset
	if seq >= b.nextSeq || offset > b.last {
		return 0, next, ErrNotArrived
	}
	f := b.frame(offset)
	if f.size() == 0 || f.seq() != seq || offset < b.first {
		return b.readFirst(data)
	}
	return b.readOffset(data, offset)
}
func (b *Buffer) ReadFirst(data []byte) (n int, next Cursor, err error) {
	b.mu.RLock()
	defer b.mu.RUnlock()
	return b.readOffset(data, b.first)
}
func (b *Buffer) readFirst(data []byte) (n int, next Cursor, err error) {
	return b.readOffset(data, b.first)
}
func (b *Buffer) readOffset(data []byte, offset uint64) (n int, next Cursor, err error) {
	if b.biggest == 0 {
		return 0, next, ErrNotArrived
	}
	f := b.frame(offset)
	d := f.data()
	n = copy(data, d)
	if n != len(d) {
		err = ErrPartialData
	}
	next.offset = b.nextFrameOffset(offset)
	if next.offset-offset == b.capacity {
		next.seq = b.nextSeq
		return
	}
	if offset == b.last {
		next.seq = b.nextSeq
	} else {
		nextf := b.frame(next.offset)
		next.seq = nextf.seq()
	}
	return
}
var pageSize uint64
func init() {
	pageSize = uint64(os.Getpagesize())
}