johnsonjh/jleveldb

View on GitHub
leveldb/db_util.go

Summary

Maintainability
A
2 hrs
Test Coverage
// Copyright © 2012, Suryandaru Triandana <syndtr@gmail.com>
// Copyright © 2021, Jeffrey H. Johnson <trnsz@pobox.com>
//
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package leveldb

import (
    "github.com/johnsonjh/jleveldb/leveldb/errors"
    "github.com/johnsonjh/jleveldb/leveldb/iterator"
    "github.com/johnsonjh/jleveldb/leveldb/opt"
    "github.com/johnsonjh/jleveldb/leveldb/storage"
    "github.com/johnsonjh/jleveldb/leveldb/util"
)

// Reader is the interface that wraps basic Get and NewIterator methods.
// This interface implemented by both DB and Snapshot.
type Reader interface {
    Get(key []byte, ro *opt.ReadOptions) (value []byte, err error)
    NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator
}

// Sizes is list of size.
type Sizes []int64

// Sum returns sum of the sizes.
func (sizes Sizes) Sum() int64 {
    var sum int64
    for _, size := range sizes {
        sum += size
    }
    return sum
}

// Logging.
func (db *DB) log(v ...interface{})                 { db.s.log(v...) }
func (db *DB) logf(format string, v ...interface{}) { db.s.logf(format, v...) }

// Check and clean files.
func (db *DB) checkAndCleanFiles() error {
    v := db.s.version()
    defer v.release()

    tmap := make(map[int64]bool)
    for _, tables := range v.levels {
        for _, t := range tables {
            tmap[t.fd.Num] = false
        }
    }

    fds, err := db.s.stor.List(storage.TypeAll)
    if err != nil {
        return err
    }

    var nt int
    var rem []storage.FileDesc
    for _, fd := range fds {
        keep := true
        switch fd.Type {
        case storage.TypeManifest:
            keep = fd.Num >= db.s.manifestFd.Num
        case storage.TypeJournal:
            if !db.frozenJournalFd.Zero() {
                keep = fd.Num >= db.frozenJournalFd.Num
            } else {
                keep = fd.Num >= db.journalFd.Num
            }
        case storage.TypeTable:
            _, keep = tmap[fd.Num]
            if keep {
                tmap[fd.Num] = true
                nt++
            }
        }

        if !keep {
            rem = append(rem, fd)
        }
    }

    if nt != len(tmap) {
        var mfds []storage.FileDesc
        for num, present := range tmap {
            if !present {
                mfds = append(mfds, storage.FileDesc{Type: storage.TypeTable, Num: num})
                db.logf("db@janitor table missing @%d", num)
            }
        }
        return errors.NewErrCorrupted(storage.FileDesc{}, &errors.ErrMissingFiles{Fds: mfds})
    }

    db.logf("db@janitor F·%d G·%d", len(fds), len(rem))
    for _, fd := range rem {
        db.logf("db@janitor removing %s-%d", fd.Type, fd.Num)
        if err := db.s.stor.Remove(fd); err != nil {
            return err
        }
    }
    return nil
}