// Opens table. It returns a cache object, which should // be released after use. func (t *tOps) open(f *tFile) (c cache.Object, err error) { num := f.file.Num() c, ok := t.cacheNS.Get(num, func() (ok bool, value interface{}, charge int, fin cache.SetFin) { var r storage.Reader r, err = f.file.Open() if err != nil { return } o := t.s.o var cacheNS cache.Namespace if bc := o.GetBlockCache(); bc != nil { cacheNS = bc.GetNamespace(num) } ok = true value = table.NewReader(r, int64(f.size), cacheNS, o) charge = 1 fin = func() { r.Close() } return }) if !ok && err == nil { err = ErrClosed } return }
// Recover recovers and opens a DB with missing or corrupted manifest files // for the given storage. It will ignore any manifest files, valid or not. // The DB must already exist or it will returns an error. // Also, Recover will ignore ErrorIfMissing and ErrorIfExist options. // // The DB must be closed after use, by calling Close method. func Recover(p storage.Storage, o *opt.Options) (db *DB, err error) { s, err := newSession(p, o) if err != nil { return } defer func() { if err != nil { s.close() s.release() } }() // get all files ff0, err := s.getFiles(storage.TypeAll) if err != nil { return } ff := files(ff0) ff.sort() s.logf("db@recovery F·%d", len(ff)) rec := new(sessionRecord) // recover tables var nt *tFile for _, f := range ff { if f.Type() != storage.TypeTable { continue } var r storage.Reader r, err = f.Open() if err != nil { return } var size int64 size, err = r.Seek(0, 2) r.Close() if err != nil { return } t := newTFile(f, uint64(size), nil, nil) iter := s.tops.newIterator(t, nil) // min ikey if iter.First() { t.min = iter.Key() } else { err = iter.Error() iter.Release() if err != nil { return } else { continue } } // max ikey if iter.Last() { t.max = iter.Key() } else { err = iter.Error() iter.Release() if err != nil { return } else { continue } } iter.Release() s.logf("db@recovery found table @%d S·%s %q:%q", t.file.Num(), shortenb(int(t.size)), t.min, t.max) // add table to level 0 rec.addTableFile(0, t) nt = t } // extract largest seq number from newest table if nt != nil { var lseq uint64 iter := s.tops.newIterator(nt, nil) for iter.Next() { seq, _, ok := iKey(iter.Key()).parseNum() if !ok { continue } if seq > lseq { lseq = seq } } iter.Release() rec.setSeq(lseq) } // set file num based on largest one s.stFileNum = ff[len(ff)-1].Num() + 1 // create brand new manifest err = s.create() if err != nil { return } // commit record err = s.commit(rec) if err != nil { return } return openDB(s) }