2018-09-18 08:41:06 +00:00
|
|
|
// Copyright (C) 2018 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 https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
keyPrefixLen = 1
|
|
|
|
keyFolderLen = 4 // indexed
|
|
|
|
keyDeviceLen = 4 // indexed
|
|
|
|
keySequenceLen = 8
|
|
|
|
keyHashLen = 32
|
|
|
|
|
|
|
|
maxInt64 int64 = 1<<63 - 1
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
KeyTypeDevice = 0
|
|
|
|
KeyTypeGlobal = 1
|
|
|
|
KeyTypeBlock = 2
|
|
|
|
KeyTypeDeviceStatistic = 3
|
|
|
|
KeyTypeFolderStatistic = 4
|
|
|
|
KeyTypeVirtualMtime = 5
|
|
|
|
KeyTypeFolderIdx = 6
|
|
|
|
KeyTypeDeviceIdx = 7
|
|
|
|
KeyTypeIndexID = 8
|
|
|
|
KeyTypeFolderMeta = 9
|
|
|
|
KeyTypeMiscData = 10
|
|
|
|
KeyTypeSequence = 11
|
|
|
|
KeyTypeNeed = 12
|
|
|
|
)
|
|
|
|
|
|
|
|
type keyer interface {
|
|
|
|
// device file key stuff
|
|
|
|
GenerateDeviceFileKey(key, folder, device, name []byte) deviceFileKey
|
|
|
|
NameFromDeviceFileKey(key []byte) []byte
|
|
|
|
DeviceFromDeviceFileKey(key []byte) ([]byte, bool)
|
|
|
|
FolderFromDeviceFileKey(key []byte) ([]byte, bool)
|
|
|
|
|
|
|
|
// global version key stuff
|
|
|
|
GenerateGlobalVersionKey(key, folder, name []byte) globalVersionKey
|
|
|
|
NameFromGlobalVersionKey(key []byte) []byte
|
|
|
|
FolderFromGlobalVersionKey(key []byte) ([]byte, bool)
|
|
|
|
|
|
|
|
// file need index
|
|
|
|
GenerateNeedFileKey(key, folder, name []byte) needFileKey
|
|
|
|
|
|
|
|
// file sequence index
|
|
|
|
GenerateSequenceKey(key, folder []byte, seq int64) sequenceKey
|
|
|
|
SequenceFromSequenceKey(key []byte) int64
|
|
|
|
|
|
|
|
// index IDs
|
|
|
|
GenerateIndexIDKey(key, device, folder []byte) indexIDKey
|
|
|
|
DeviceFromIndexIDKey(key []byte) ([]byte, bool)
|
|
|
|
|
|
|
|
// Mtimes
|
|
|
|
GenerateMtimesKey(key, folder []byte) mtimesKey
|
|
|
|
|
|
|
|
// Folder metadata
|
|
|
|
GenerateFolderMetaKey(key, folder []byte) folderMetaKey
|
|
|
|
}
|
|
|
|
|
|
|
|
// defaultKeyer implements our key scheme. It needs folder and device
|
|
|
|
// indexes.
|
|
|
|
type defaultKeyer struct {
|
|
|
|
folderIdx *smallIndex
|
|
|
|
deviceIdx *smallIndex
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDefaultKeyer(folderIdx, deviceIdx *smallIndex) defaultKeyer {
|
|
|
|
return defaultKeyer{
|
|
|
|
folderIdx: folderIdx,
|
|
|
|
deviceIdx: deviceIdx,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type deviceFileKey []byte
|
|
|
|
|
2018-10-11 10:09:44 +00:00
|
|
|
func (k deviceFileKey) WithoutNameAndDevice() []byte {
|
|
|
|
return k[:keyPrefixLen+keyFolderLen]
|
2018-09-18 08:41:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateDeviceFileKey(key, folder, device, name []byte) deviceFileKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyFolderLen+keyDeviceLen+len(name))
|
|
|
|
key[0] = KeyTypeDevice
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.folderIdx.ID(folder))
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen+keyFolderLen:], k.deviceIdx.ID(device))
|
|
|
|
copy(key[keyPrefixLen+keyFolderLen+keyDeviceLen:], name)
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) NameFromDeviceFileKey(key []byte) []byte {
|
|
|
|
return key[keyPrefixLen+keyFolderLen+keyDeviceLen:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) DeviceFromDeviceFileKey(key []byte) ([]byte, bool) {
|
|
|
|
return k.deviceIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen+keyFolderLen:]))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) FolderFromDeviceFileKey(key []byte) ([]byte, bool) {
|
|
|
|
return k.folderIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen:]))
|
|
|
|
}
|
|
|
|
|
|
|
|
type globalVersionKey []byte
|
|
|
|
|
|
|
|
func (k globalVersionKey) WithoutName() []byte {
|
|
|
|
return k[:keyPrefixLen+keyFolderLen]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateGlobalVersionKey(key, folder, name []byte) globalVersionKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyFolderLen+len(name))
|
|
|
|
key[0] = KeyTypeGlobal
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.folderIdx.ID(folder))
|
|
|
|
copy(key[keyPrefixLen+keyFolderLen:], name)
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) NameFromGlobalVersionKey(key []byte) []byte {
|
|
|
|
return key[keyPrefixLen+keyFolderLen:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) FolderFromGlobalVersionKey(key []byte) ([]byte, bool) {
|
|
|
|
return k.folderIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen:]))
|
|
|
|
}
|
|
|
|
|
|
|
|
type needFileKey []byte
|
|
|
|
|
|
|
|
func (k needFileKey) WithoutName() []byte {
|
|
|
|
return k[:keyPrefixLen+keyFolderLen]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateNeedFileKey(key, folder, name []byte) needFileKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyFolderLen+len(name))
|
|
|
|
key[0] = KeyTypeNeed
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.folderIdx.ID(folder))
|
|
|
|
copy(key[keyPrefixLen+keyFolderLen:], name)
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
type sequenceKey []byte
|
|
|
|
|
|
|
|
func (k sequenceKey) WithoutSequence() []byte {
|
|
|
|
return k[:keyPrefixLen+keyFolderLen]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateSequenceKey(key, folder []byte, seq int64) sequenceKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyFolderLen+keySequenceLen)
|
|
|
|
key[0] = KeyTypeSequence
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.folderIdx.ID(folder))
|
|
|
|
binary.BigEndian.PutUint64(key[keyPrefixLen+keyFolderLen:], uint64(seq))
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) SequenceFromSequenceKey(key []byte) int64 {
|
|
|
|
return int64(binary.BigEndian.Uint64(key[keyPrefixLen+keyFolderLen:]))
|
|
|
|
}
|
|
|
|
|
|
|
|
type indexIDKey []byte
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateIndexIDKey(key, device, folder []byte) indexIDKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyDeviceLen+keyFolderLen)
|
|
|
|
key[0] = KeyTypeIndexID
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.deviceIdx.ID(device))
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen+keyDeviceLen:], k.folderIdx.ID(folder))
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k defaultKeyer) DeviceFromIndexIDKey(key []byte) ([]byte, bool) {
|
|
|
|
return k.deviceIdx.Val(binary.BigEndian.Uint32(key[keyPrefixLen:]))
|
|
|
|
}
|
|
|
|
|
|
|
|
type mtimesKey []byte
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateMtimesKey(key, folder []byte) mtimesKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyFolderLen)
|
|
|
|
key[0] = KeyTypeVirtualMtime
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.folderIdx.ID(folder))
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
type folderMetaKey []byte
|
|
|
|
|
|
|
|
func (k defaultKeyer) GenerateFolderMetaKey(key, folder []byte) folderMetaKey {
|
|
|
|
key = resize(key, keyPrefixLen+keyFolderLen)
|
|
|
|
key[0] = KeyTypeFolderMeta
|
|
|
|
binary.BigEndian.PutUint32(key[keyPrefixLen:], k.folderIdx.ID(folder))
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
|
|
|
// resize returns a byte slice of the specified size, reusing bs if possible
|
|
|
|
func resize(bs []byte, size int) []byte {
|
|
|
|
if cap(bs) < size {
|
|
|
|
return make([]byte, size)
|
|
|
|
}
|
|
|
|
return bs[:size]
|
|
|
|
}
|