package badger
import (
"encoding/binary"
"os"
"path/filepath"
"sort"
"sync"
"github.com/dgraph-io/badger/v4/y"
"github.com/dgraph-io/ristretto/v2/z"
)
type discardStats struct {
sync .Mutex
*z .MmapFile
opt Options
nextEmptySlot int
}
const discardFname string = "DISCARD"
func InitDiscardStats (opt Options ) (*discardStats , error ) {
fname := filepath .Join (opt .ValueDir , discardFname )
mf , err := z .OpenMmapFile (fname , os .O_CREATE |os .O_RDWR , 1 <<20 )
lf := &discardStats {
MmapFile : mf ,
opt : opt ,
}
if err == z .NewFile {
lf .zeroOut ()
} else if err != nil {
return nil , y .Wrapf (err , "while opening file: %s\n" , discardFname )
}
for slot := 0 ; slot < lf .maxSlot (); slot ++ {
if lf .get (16 *slot ) == 0 {
lf .nextEmptySlot = slot
break
}
}
sort .Sort (lf )
opt .Infof ("Discard stats nextEmptySlot: %d\n" , lf .nextEmptySlot )
return lf , nil
}
func (lf *discardStats ) Len () int {
return lf .nextEmptySlot
}
func (lf *discardStats ) Less (i , j int ) bool {
return lf .get (16 *i ) < lf .get (16 *j )
}
func (lf *discardStats ) Swap (i , j int ) {
left := lf .Data [16 *i : 16 *i +16 ]
right := lf .Data [16 *j : 16 *j +16 ]
var tmp [16 ]byte
copy (tmp [:], left )
copy (left , right )
copy (right , tmp [:])
}
func (lf *discardStats ) get (offset int ) uint64 {
return binary .BigEndian .Uint64 (lf .Data [offset : offset +8 ])
}
func (lf *discardStats ) set (offset int , val uint64 ) {
binary .BigEndian .PutUint64 (lf .Data [offset :offset +8 ], val )
}
func (lf *discardStats ) zeroOut () {
lf .set (lf .nextEmptySlot *16 , 0 )
lf .set (lf .nextEmptySlot *16 +8 , 0 )
}
func (lf *discardStats ) maxSlot () int {
return len (lf .Data ) / 16
}
func (lf *discardStats ) Update (fidu uint32 , discard int64 ) int64 {
fid := uint64 (fidu )
lf .Lock ()
defer lf .Unlock ()
idx := sort .Search (lf .nextEmptySlot , func (slot int ) bool {
return lf .get (slot *16 ) >= fid
})
if idx < lf .nextEmptySlot && lf .get (idx *16 ) == fid {
off := idx *16 + 8
curDisc := lf .get (off )
if discard == 0 {
return int64 (curDisc )
}
if discard < 0 {
lf .set (off , 0 )
return 0
}
lf .set (off , curDisc +uint64 (discard ))
return int64 (curDisc + uint64 (discard ))
}
if discard <= 0 {
return 0
}
idx = lf .nextEmptySlot
lf .set (idx *16 , fid )
lf .set (idx *16 +8 , uint64 (discard ))
lf .nextEmptySlot ++
for lf .nextEmptySlot >= lf .maxSlot () {
y .Check (lf .Truncate (2 * int64 (len (lf .Data ))))
}
lf .zeroOut ()
sort .Sort (lf )
return discard
}
func (lf *discardStats ) Iterate (f func (fid , stats uint64 )) {
for slot := 0 ; slot < lf .nextEmptySlot ; slot ++ {
idx := 16 * slot
f (lf .get (idx ), lf .get (idx +8 ))
}
}
func (lf *discardStats ) MaxDiscard () (uint32 , int64 ) {
lf .Lock ()
defer lf .Unlock ()
var maxFid , maxVal uint64
lf .Iterate (func (fid , val uint64 ) {
if maxVal < val {
maxVal = val
maxFid = fid
}
})
return uint32 (maxFid ), int64 (maxVal )
}
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 .