| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- // Copyright (C) 2014 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at http://mozilla.org/MPL/2.0/.
- //go:generate -command genxdr go run ../../Godeps/_workspace/src/github.com/calmh/xdr/cmd/genxdr/main.go
- //go:generate genxdr -o leveldb_xdr.go leveldb.go
- package db
- import (
- "bytes"
- "fmt"
- "github.com/syncthing/syncthing/lib/protocol"
- "github.com/syncthing/syncthing/lib/sync"
- "github.com/syndtr/goleveldb/leveldb"
- "github.com/syndtr/goleveldb/leveldb/opt"
- )
- var (
- clockTick int64
- clockMut = sync.NewMutex()
- )
- func clock(v int64) int64 {
- clockMut.Lock()
- defer clockMut.Unlock()
- if v > clockTick {
- clockTick = v + 1
- } else {
- clockTick++
- }
- return clockTick
- }
- const (
- KeyTypeDevice = iota
- KeyTypeGlobal
- KeyTypeBlock
- KeyTypeDeviceStatistic
- KeyTypeFolderStatistic
- KeyTypeVirtualMtime
- )
- type fileVersion struct {
- version protocol.Vector
- device []byte
- }
- type versionList struct {
- versions []fileVersion
- }
- func (l versionList) String() string {
- var b bytes.Buffer
- var id protocol.DeviceID
- b.WriteString("{")
- for i, v := range l.versions {
- if i > 0 {
- b.WriteString(", ")
- }
- copy(id[:], v.device)
- fmt.Fprintf(&b, "{%d, %v}", v.version, id)
- }
- b.WriteString("}")
- return b.String()
- }
- type fileList []protocol.FileInfo
- func (l fileList) Len() int {
- return len(l)
- }
- func (l fileList) Swap(a, b int) {
- l[a], l[b] = l[b], l[a]
- }
- func (l fileList) Less(a, b int) bool {
- return l[a].Name < l[b].Name
- }
- type dbReader interface {
- Get([]byte, *opt.ReadOptions) ([]byte, error)
- }
- // Flush batches to disk when they contain this many records.
- const batchFlushSize = 64
- // deviceKey returns a byte slice encoding the following information:
- // keyTypeDevice (1 byte)
- // folder (64 bytes)
- // device (32 bytes)
- // name (variable size)
- func deviceKey(folder, device, file []byte) []byte {
- return deviceKeyInto(nil, folder, device, file)
- }
- func deviceKeyInto(k []byte, folder, device, file []byte) []byte {
- reqLen := 1 + 64 + 32 + len(file)
- if len(k) < reqLen {
- k = make([]byte, reqLen)
- }
- k[0] = KeyTypeDevice
- if len(folder) > 64 {
- panic("folder name too long")
- }
- copy(k[1:], []byte(folder))
- copy(k[1+64:], device[:])
- copy(k[1+64+32:], []byte(file))
- return k[:reqLen]
- }
- func deviceKeyName(key []byte) []byte {
- return key[1+64+32:]
- }
- func deviceKeyFolder(key []byte) []byte {
- folder := key[1 : 1+64]
- izero := bytes.IndexByte(folder, 0)
- if izero < 0 {
- return folder
- }
- return folder[:izero]
- }
- func deviceKeyDevice(key []byte) []byte {
- return key[1+64 : 1+64+32]
- }
- // globalKey returns a byte slice encoding the following information:
- // keyTypeGlobal (1 byte)
- // folder (64 bytes)
- // name (variable size)
- func globalKey(folder, file []byte) []byte {
- k := make([]byte, 1+64+len(file))
- k[0] = KeyTypeGlobal
- if len(folder) > 64 {
- panic("folder name too long")
- }
- copy(k[1:], []byte(folder))
- copy(k[1+64:], []byte(file))
- return k
- }
- func globalKeyName(key []byte) []byte {
- return key[1+64:]
- }
- func globalKeyFolder(key []byte) []byte {
- folder := key[1 : 1+64]
- izero := bytes.IndexByte(folder, 0)
- if izero < 0 {
- return folder
- }
- return folder[:izero]
- }
- func getFile(db dbReader, folder, device, file []byte) (protocol.FileInfo, bool) {
- nk := deviceKey(folder, device, file)
- bs, err := db.Get(nk, nil)
- if err == leveldb.ErrNotFound {
- return protocol.FileInfo{}, false
- }
- if err != nil {
- panic(err)
- }
- var f protocol.FileInfo
- err = f.UnmarshalXDR(bs)
- if err != nil {
- panic(err)
- }
- return f, true
- }
|