Esempio n. 1
0
func readFooter(r io.ReaderAt, size uint64) (mi, ii *bInfo, err error) {
	if size < uint64(footerSize) {
		err = errors.ErrInvalid("file is too short to be an sstable")
		return
	}

	buf := make([]byte, footerSize)
	n, err := r.ReadAt(buf, int64(size)-footerSize)
	if err != nil {
		return
	}

	if bytes.Compare(buf[handlesSize:], magicBytes) != 0 {
		err = errors.ErrInvalid("not an sstable (bad magic number)")
		return
	}

	mi = new(bInfo)
	n, err = mi.decodeFrom(buf)
	if err != nil {
		return
	}

	ii = new(bInfo)
	n, err = ii.decodeFrom(buf[n:])
	if err != nil {
		return
	}

	return
}
Esempio n. 2
0
// GetProperty used to query exported database state.
//
// Valid property names include:
//
//  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
//     where <N> is an ASCII representation of a level number (e.g. "0").
//  "leveldb.stats" - returns a multi-line string that describes statistics
//     about the internal operation of the DB.
//  "leveldb.sstables" - returns a multi-line string that describes all
//     of the sstables that make up the db contents.
func (d *DB) GetProperty(prop string) (value string, err error) {
	err = d.rok()
	if err != nil {
		return
	}

	const prefix = "leveldb."
	if !strings.HasPrefix(prop, prefix) {
		return "", errors.ErrInvalid("unknown property: " + prop)
	}

	p := prop[len(prefix):]

	switch s := d.s; true {
	case strings.HasPrefix(p, "num-files-at-level"):
		var level uint
		var rest string
		n, _ := fmt.Scanf("%d%s", &level, &rest)
		if n != 1 || level >= kNumLevels {
			return "", errors.ErrInvalid("invalid property: " + prop)
		}
		value = fmt.Sprint(s.version().tLen(int(level)))
	case p == "stats":
		v := s.version()
		value = "Compactions\n" +
			" Level |   Tables   |    Size(MB)   |    Time(sec)  |    Read(MB)   |   Write(MB)\n" +
			"-------+------------+---------------+---------------+---------------+---------------\n"
		for level, tt := range v.tables {
			duration, read, write := d.cstats[level].get()
			if len(tt) == 0 && duration == 0 {
				continue
			}
			value += fmt.Sprintf(" %3d   | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n",
				level, len(tt), float64(tt.size())/1048576.0, duration.Seconds(),
				float64(read)/1048576.0, float64(write)/1048576.0)
		}
	case p == "sstables":
		v := s.version()
		for level, tt := range v.tables {
			value += fmt.Sprintf("--- level %d ---\n", level)
			for _, t := range tt {
				value += fmt.Sprintf("%d:%d[%q .. %q]\n", t.file.Num(), t.size, t.min, t.max)
			}
		}
	default:
		return "", errors.ErrInvalid("unknown property: " + prop)
	}

	return
}
Esempio n. 3
0
// Recover a database session; need external synchronization.
func (s *session) recover() (err error) {
	file, err := s.stor.GetManifest()
	if err != nil {
		return
	}

	r, err := newJournalReader(file, true, s.journalDropFunc("manifest", file.Num()))
	if err != nil {
		return
	}
	defer r.close()

	cmp := s.cmp.cmp.Name()
	staging := s.version_NB().newStaging()
	srec := new(sessionRecord)

	for r.journal.Next() {
		rec := new(sessionRecord)
		err = rec.decode(r.journal.Record())
		if err != nil {
			continue
		}

		if rec.hasComparer && rec.comparer != cmp {
			return errors.ErrInvalid("invalid comparer, " +
				"want '" + cmp + "', " +
				"got '" + rec.comparer + "'")
		}

		// save compact pointers
		for _, rp := range rec.compactPointers {
			s.stCPtrs[rp.level] = iKey(rp.key)
		}

		// commit record to version staging
		staging.commit(rec)

		if rec.hasJournalNum {
			srec.setJournalNum(rec.journalNum)
		}
		if rec.hasPrevJournalNum {
			srec.setPrevJournalNum(rec.prevJournalNum)
		}
		if rec.hasNextNum {
			srec.setNextNum(rec.nextNum)
		}
		if rec.hasSeq {
			srec.setSeq(rec.seq)
		}
	}

	// check for error in journal reader
	err = r.journal.Error()
	if err != nil {
		return
	}

	switch false {
	case srec.hasNextNum:
		err = errors.ErrCorrupt("manifest missing next file number")
	case srec.hasJournalNum:
		err = errors.ErrCorrupt("manifest missing journal file number")
	case srec.hasSeq:
		err = errors.ErrCorrupt("manifest missing seq number")
	}
	if err != nil {
		return
	}

	s.manifest = &journalWriter{file: file}
	s.setVersion(staging.finish())
	s.setFileNum(srec.nextNum)
	s.recordCommited(srec)

	return
}
Esempio n. 4
0
func (p *sessionRecord) decodeFrom(r readByteReader) (err error) {
	for err == nil {
		var tag uint64
		tag, err = binary.ReadUvarint(r)
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return
		}

		switch tag {
		case tagComparer:
			var cmp []byte
			cmp, err = readBytes(r)
			if err == nil {
				p.comparer = string(cmp)
				p.hasComparer = true
			}
		case tagLogNum:
			p.logNum, err = binary.ReadUvarint(r)
			if err == nil {
				p.hasLogNum = true
			}
		case tagPrevLogNum:
			err = errors.ErrInvalid("unsupported db format")
			break
		case tagNextNum:
			p.nextNum, err = binary.ReadUvarint(r)
			if err == nil {
				p.hasNextNum = true
			}
		case tagSeq:
			var seq uint64
			seq, err = binary.ReadUvarint(r)
			if err == nil {
				p.seq = seq
				p.hasSeq = true
			}
		case tagCompactPointer:
			var level uint64
			var b []byte
			level, err = binary.ReadUvarint(r)
			if err != nil {
				break
			}
			b, err = readBytes(r)
			if err != nil {
				break
			}
			p.addCompactPointer(int(level), b)
		case tagNewTable:
			var level, num, size uint64
			var b []byte
			level, err = binary.ReadUvarint(r)
			if err != nil {
				break
			}
			num, err = binary.ReadUvarint(r)
			if err != nil {
				break
			}
			size, err = binary.ReadUvarint(r)
			if err != nil {
				break
			}
			b, err = readBytes(r)
			if err != nil {
				break
			}
			min := iKey(b)
			b, err = readBytes(r)
			if err != nil {
				break
			}
			max := iKey(b)
			p.addTable(int(level), num, size, min, max)
		case tagDeletedTable:
			var level, num uint64
			level, err = binary.ReadUvarint(r)
			if err != nil {
				break
			}
			num, err = binary.ReadUvarint(r)
			if err != nil {
				break
			}
			p.deleteTable(int(level), num)
		}
	}

	return
}