package z
import (
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"path/filepath"
)
type MmapFile struct {
Data []byte
Fd *os .File
}
var NewFile = errors .New ("Create a new file" )
func OpenMmapFileUsing (fd *os .File , sz int , writable bool ) (*MmapFile , error ) {
filename := fd .Name ()
fi , err := fd .Stat ()
if err != nil {
return nil , errors .Join (err , fmt .Errorf ("cannot stat file: %s" , filename ))
}
var rerr error
fileSize := fi .Size ()
if sz > 0 && fileSize == 0 {
if err := fd .Truncate (int64 (sz )); err != nil {
return nil , errors .Join (err , errors .New ("error while truncation" ))
}
fileSize = int64 (sz )
rerr = NewFile
}
buf , err := Mmap (fd , writable , fileSize )
if err != nil {
return nil , errors .Join (err , fmt .Errorf ("while mmapping %s with size: %d" , fd .Name (), fileSize ))
}
if fileSize == 0 {
dir , _ := filepath .Split (filename )
if err := SyncDir (dir ); err != nil {
return nil , err
}
}
return &MmapFile {
Data : buf ,
Fd : fd ,
}, rerr
}
func OpenMmapFile (filename string , flag int , maxSz int ) (*MmapFile , error ) {
fd , err := os .OpenFile (filename , flag , 0666 )
if err != nil {
return nil , errors .Join (err , fmt .Errorf ("unable to open: %s" , filename ))
}
writable := true
if flag == os .O_RDONLY {
writable = false
}
return OpenMmapFileUsing (fd , maxSz , writable )
}
type mmapReader struct {
Data []byte
offset int
}
func (mr *mmapReader ) Read (buf []byte ) (int , error ) {
if mr .offset > len (mr .Data ) {
return 0 , io .EOF
}
n := copy (buf , mr .Data [mr .offset :])
mr .offset += n
if n < len (buf ) {
return n , io .EOF
}
return n , nil
}
func (m *MmapFile ) NewReader (offset int ) io .Reader {
return &mmapReader {
Data : m .Data ,
offset : offset ,
}
}
func (m *MmapFile ) Bytes (off , sz int ) ([]byte , error ) {
if len (m .Data [off :]) < sz {
return nil , io .EOF
}
return m .Data [off : off +sz ], nil
}
func (m *MmapFile ) Slice (offset int ) []byte {
sz := binary .BigEndian .Uint32 (m .Data [offset :])
start := offset + 4
next := start + int (sz )
if next > len (m .Data ) {
return []byte {}
}
res := m .Data [start :next ]
return res
}
func (m *MmapFile ) AllocateSlice (sz , offset int ) ([]byte , int , error ) {
start := offset + 4
if start +sz > len (m .Data ) {
const oneGB = 1 << 30
growBy := len (m .Data )
if growBy > oneGB {
growBy = oneGB
}
if growBy < sz +4 {
growBy = sz + 4
}
if err := m .Truncate (int64 (len (m .Data ) + growBy )); err != nil {
return nil , 0 , err
}
}
binary .BigEndian .PutUint32 (m .Data [offset :], uint32 (sz ))
return m .Data [start : start +sz ], start + sz , nil
}
func (m *MmapFile ) Sync () error {
if m == nil {
return nil
}
return Msync (m .Data )
}
func (m *MmapFile ) Delete () error {
if m .Fd == nil {
return nil
}
if err := Munmap (m .Data ); err != nil {
return fmt .Errorf ("while munmap file: %s, error: %v\n" , m .Fd .Name (), err )
}
m .Data = nil
if err := m .Fd .Truncate (0 ); err != nil {
return fmt .Errorf ("while truncate file: %s, error: %v\n" , m .Fd .Name (), err )
}
if err := m .Fd .Close (); err != nil {
return fmt .Errorf ("while close file: %s, error: %v\n" , m .Fd .Name (), err )
}
return os .Remove (m .Fd .Name ())
}
func (m *MmapFile ) Close (maxSz int64 ) error {
if m .Fd == nil {
return nil
}
if err := m .Sync (); err != nil {
return fmt .Errorf ("while sync file: %s, error: %v\n" , m .Fd .Name (), err )
}
if err := Munmap (m .Data ); err != nil {
return fmt .Errorf ("while munmap file: %s, error: %v\n" , m .Fd .Name (), err )
}
if maxSz >= 0 {
if err := m .Fd .Truncate (maxSz ); err != nil {
return fmt .Errorf ("while truncate file: %s, error: %v\n" , m .Fd .Name (), err )
}
}
return m .Fd .Close ()
}
func SyncDir (dir string ) error {
df , err := os .Open (dir )
if err != nil {
return errors .Join (err , fmt .Errorf ("while opening %s" , dir ))
}
if err := df .Sync (); err != nil {
return errors .Join (err , fmt .Errorf ("while syncing %s" , dir ))
}
if err := df .Close (); err != nil {
return errors .Join (err , fmt .Errorf ("while closing %s" , dir ))
}
return nil
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .