func (f *bitFiler) WriteAt(b []byte, off int64) (n int, err error) { off0 := off pgI := off >> bfBits pgO := int(off & bfMask) n = len(b) rem := n var nc int for rem != 0 { pg := f.m[pgI] if pg == nil { pg = &bitPage{} if f.parent != nil { _, err = f.parent.ReadAt(pg.data[:], off&^bfMask) if err != nil && !fileutil.IsEOF(err) { return } err = nil } f.m[pgI] = pg } nc = copy(pg.data[pgO:], b) pgI++ pg.dirty = true for i := pgO; i < pgO+nc; i++ { pg.flags[i>>3] |= bitmask[i&7] } pgO = 0 rem -= nc b = b[nc:] off += int64(nc) } f.size = mathutil.MaxInt64(f.size, off0+int64(n)) return }
// WriteAt implements Filer. func (f *MemFiler) WriteAt(b []byte, off int64) (n int, err error) { pgI := off >> pgBits pgO := int(off & pgMask) n = len(b) rem := n var nc int for rem != 0 { if pgO == 0 && rem >= pgSize && bytes.Equal(b[:pgSize], zeroPage[:]) { delete(f.m, pgI) nc = pgSize } else { pg := f.m[pgI] if pg == nil { pg = new([pgSize]byte) f.m[pgI] = pg } nc = copy((*pg)[pgO:], b) } pgI++ pgO = 0 rem -= nc b = b[nc:] } f.size = mathutil.MaxInt64(f.size, off+int64(n)) return }
// Size implements Filer. func (f *InnerFiler) Size() (int64, error) { sz, err := f.outer.Size() if err != nil { return 0, err } return mathutil.MaxInt64(sz-f.off, 0), nil }
func (f *File) writeAt(b []byte, off int64, bits bool) (n int, err error) { var fsize int64 a := (*Array)(f) if !bits { fsize, err = f.Size() if err != nil { return } } pgI := off >> pgBits pgO := int(off & pgMask) rem := len(b) var nc int for rem != 0 { if pgO == 0 && rem >= pgSize && bytes.Equal(b[:pgSize], zeroPage[:]) { if err = a.Delete(pgI); err != nil { return } nc = pgSize n += nc } else { v, err := a.Get(pgI) if err != nil { return n, err } pg, _ := v.([]byte) if len(pg) == 0 { pg = make([]byte, pgSize) } nc = copy(pg[pgO:], b) n += nc if err = a.Set(pg, pgI); err != nil { return n, err } } pgI++ pgO = 0 rem -= nc b = b[nc:] } if !bits { if newSize := mathutil.MaxInt64(fsize, off+int64(n)); newSize != fsize { return n, a.Set(newSize, fSize) } } return }
// WriteAt implements Filer. func (f *SimpleFileFiler) WriteAt(b []byte, off int64) (n int, err error) { if f.size < 0 { // boot fi, err := os.Stat(f.file.Name()) if err != nil { return 0, err } f.size = fi.Size() } f.size = mathutil.MaxInt64(f.size, int64(len(b))+off) return f.file.WriteAt(b, off) }
// NewACIDFiler0 returns a newly created ACIDFiler0 with WAL in wal. // // If the WAL is zero sized then a previous clean shutdown of db is taken for // granted and no recovery procedure is taken. // // If the WAL is of non zero size then it is checked for having a // commited/fully finished transaction not yet been reflected in db. If such // transaction exists it's committed to db. If the recovery process finishes // successfully, the WAL is truncated to zero size and fsync'ed prior to return // from NewACIDFiler0. func NewACIDFiler(db Filer, wal *os.File) (r *ACIDFiler0, err error) { fi, err := wal.Stat() if err != nil { return } r = &ACIDFiler0{wal: wal} if fi.Size() != 0 { if err = r.recoverDb(db); err != nil { return } } acidWriter := (*acidWriter0)(r) if r.RollbackFiler, err = NewRollbackFiler( db, func(sz int64) (err error) { // Checkpoint if err = acidWriter.writePacket([]interface{}{wpt00Checkpoint, sz}); err != nil { return } if err = r.bwal.Flush(); err != nil { return } r.bwal = nil if err = r.wal.Sync(); err != nil { return } wfi, err := r.wal.Stat() switch err != nil { case true: // unexpected, but ignored case false: r.peakWal = mathutil.MaxInt64(wfi.Size(), r.peakWal) } // Phase 1 commit complete for _, v := range r.data { if _, err := db.WriteAt(v.b, v.off); err != nil { return err } } if err = db.Truncate(sz); err != nil { return } if err = db.Sync(); err != nil { return } // Phase 2 commit complete if !r.testHook { if err = r.wal.Truncate(0); err != nil { return } if _, err = r.wal.Seek(0, 0); err != nil { return } } r.testHook = false return r.wal.Sync() }, acidWriter, ); err != nil { return } return r, nil }