mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-23 11:28:59 +00:00
parent
ac384e8a9c
commit
64ffac5671
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -49,7 +49,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
||||||
"Rev": "2b99e8d4757bf06eeab1b0485d80b8ae1c088874"
|
"Rev": "457e6f75905f7c1316afd8c43ad323f4c32b31c2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vitrun/qart/coding",
|
"ImportPath": "github.com/vitrun/qart/coding",
|
||||||
|
3
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go
generated
vendored
3
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go
generated
vendored
@ -128,7 +128,8 @@ const (
|
|||||||
type nodeState int
|
type nodeState int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nodeEffective nodeState = iota
|
nodeZero nodeState = iota
|
||||||
|
nodeEffective
|
||||||
nodeEvicted
|
nodeEvicted
|
||||||
nodeDeleted
|
nodeDeleted
|
||||||
)
|
)
|
||||||
|
56
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go
generated
vendored
56
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go
generated
vendored
@ -512,6 +512,56 @@ func TestLRUCache_Finalizer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkLRUCache_Set(b *testing.B) {
|
||||||
|
c := NewLRUCache(0)
|
||||||
|
ns := c.GetNamespace(0)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
|
set(ns, i, "", 1, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLRUCache_Get(b *testing.B) {
|
||||||
|
c := NewLRUCache(0)
|
||||||
|
ns := c.GetNamespace(0)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
|
set(ns, i, "", 1, nil)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
|
ns.Get(i, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLRUCache_Get2(b *testing.B) {
|
||||||
|
c := NewLRUCache(0)
|
||||||
|
ns := c.GetNamespace(0)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
|
set(ns, i, "", 1, nil)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
|
ns.Get(i, func() (charge int, value interface{}) {
|
||||||
|
return 0, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLRUCache_Release(b *testing.B) {
|
||||||
|
c := NewLRUCache(0)
|
||||||
|
ns := c.GetNamespace(0)
|
||||||
|
handles := make([]Handle, b.N)
|
||||||
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
|
handles[i] = set(ns, i, "", 1, nil)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for _, h := range handles {
|
||||||
|
h.Release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkLRUCache_SetRelease(b *testing.B) {
|
func BenchmarkLRUCache_SetRelease(b *testing.B) {
|
||||||
capacity := b.N / 100
|
capacity := b.N / 100
|
||||||
if capacity <= 0 {
|
if capacity <= 0 {
|
||||||
@ -521,7 +571,7 @@ func BenchmarkLRUCache_SetRelease(b *testing.B) {
|
|||||||
ns := c.GetNamespace(0)
|
ns := c.GetNamespace(0)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := uint64(0); i < uint64(b.N); i++ {
|
for i := uint64(0); i < uint64(b.N); i++ {
|
||||||
set(ns, i, nil, 1, nil).Release()
|
set(ns, i, "", 1, nil).Release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,10 +588,10 @@ func BenchmarkLRUCache_SetReleaseTwice(b *testing.B) {
|
|||||||
nb := b.N - na
|
nb := b.N - na
|
||||||
|
|
||||||
for i := uint64(0); i < uint64(na); i++ {
|
for i := uint64(0); i < uint64(na); i++ {
|
||||||
set(ns, i, nil, 1, nil).Release()
|
set(ns, i, "", 1, nil).Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := uint64(0); i < uint64(nb); i++ {
|
for i := uint64(0); i < uint64(nb); i++ {
|
||||||
set(ns, i, nil, 1, nil).Release()
|
set(ns, i, "", 1, nil).Release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
419
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru_cache.go
generated
vendored
419
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru_cache.go
generated
vendored
@ -13,6 +13,13 @@ import (
|
|||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The LLRB implementation were taken from https://github.com/petar/GoLLRB,
|
||||||
|
// which conatins the following header:
|
||||||
|
//
|
||||||
|
// Copyright 2010 Petar Maymounkov. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// lruCache represent a LRU cache state.
|
// lruCache represent a LRU cache state.
|
||||||
type lruCache struct {
|
type lruCache struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
@ -74,11 +81,7 @@ func (c *lruCache) GetNamespace(id uint64) Namespace {
|
|||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := &lruNs{
|
ns := &lruNs{lru: c, id: id}
|
||||||
lru: c,
|
|
||||||
id: id,
|
|
||||||
table: make(map[uint64]*lruNode),
|
|
||||||
}
|
|
||||||
c.table[id] = ns
|
c.table[id] = ns
|
||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
@ -130,130 +133,267 @@ func (c *lruCache) evict() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type lruNs struct {
|
type lruNs struct {
|
||||||
lru *lruCache
|
lru *lruCache
|
||||||
id uint64
|
id uint64
|
||||||
table map[uint64]*lruNode
|
rbRoot *lruNode
|
||||||
state nsState
|
state nsState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) rbGetOrCreateNode(h *lruNode, key uint64) (hn, n *lruNode) {
|
||||||
|
if h == nil {
|
||||||
|
n = &lruNode{ns: ns, key: key}
|
||||||
|
return n, n
|
||||||
|
}
|
||||||
|
|
||||||
|
if key < h.key {
|
||||||
|
hn, n = ns.rbGetOrCreateNode(h.rbLeft, key)
|
||||||
|
if hn != nil {
|
||||||
|
h.rbLeft = hn
|
||||||
|
} else {
|
||||||
|
return nil, n
|
||||||
|
}
|
||||||
|
} else if key > h.key {
|
||||||
|
hn, n = ns.rbGetOrCreateNode(h.rbRight, key)
|
||||||
|
if hn != nil {
|
||||||
|
h.rbRight = hn
|
||||||
|
} else {
|
||||||
|
return nil, n
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, h
|
||||||
|
}
|
||||||
|
|
||||||
|
if rbIsRed(h.rbRight) && !rbIsRed(h.rbLeft) {
|
||||||
|
h = rbRotLeft(h)
|
||||||
|
}
|
||||||
|
if rbIsRed(h.rbLeft) && rbIsRed(h.rbLeft.rbLeft) {
|
||||||
|
h = rbRotRight(h)
|
||||||
|
}
|
||||||
|
if rbIsRed(h.rbLeft) && rbIsRed(h.rbRight) {
|
||||||
|
rbFlip(h)
|
||||||
|
}
|
||||||
|
return h, n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) getOrCreateNode(key uint64) *lruNode {
|
||||||
|
hn, n := ns.rbGetOrCreateNode(ns.rbRoot, key)
|
||||||
|
if hn != nil {
|
||||||
|
ns.rbRoot = hn
|
||||||
|
ns.rbRoot.rbBlack = true
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) rbGetNode(key uint64) *lruNode {
|
||||||
|
h := ns.rbRoot
|
||||||
|
for h != nil {
|
||||||
|
switch {
|
||||||
|
case key < h.key:
|
||||||
|
h = h.rbLeft
|
||||||
|
case key > h.key:
|
||||||
|
h = h.rbRight
|
||||||
|
default:
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) getNode(key uint64) *lruNode {
|
||||||
|
return ns.rbGetNode(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) rbDeleteNode(h *lruNode, key uint64) *lruNode {
|
||||||
|
if h == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if key < h.key {
|
||||||
|
if h.rbLeft == nil { // key not present. Nothing to delete
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
if !rbIsRed(h.rbLeft) && !rbIsRed(h.rbLeft.rbLeft) {
|
||||||
|
h = rbMoveLeft(h)
|
||||||
|
}
|
||||||
|
h.rbLeft = ns.rbDeleteNode(h.rbLeft, key)
|
||||||
|
} else {
|
||||||
|
if rbIsRed(h.rbLeft) {
|
||||||
|
h = rbRotRight(h)
|
||||||
|
}
|
||||||
|
// If @key equals @h.key and no right children at @h
|
||||||
|
if h.key == key && h.rbRight == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if h.rbRight != nil && !rbIsRed(h.rbRight) && !rbIsRed(h.rbRight.rbLeft) {
|
||||||
|
h = rbMoveRight(h)
|
||||||
|
}
|
||||||
|
// If @key equals @h.key, and (from above) 'h.Right != nil'
|
||||||
|
if h.key == key {
|
||||||
|
var x *lruNode
|
||||||
|
h.rbRight, x = rbDeleteMin(h.rbRight)
|
||||||
|
if x == nil {
|
||||||
|
panic("logic")
|
||||||
|
}
|
||||||
|
x.rbLeft, h.rbLeft = h.rbLeft, nil
|
||||||
|
x.rbRight, h.rbRight = h.rbRight, nil
|
||||||
|
x.rbBlack = h.rbBlack
|
||||||
|
h = x
|
||||||
|
} else { // Else, @key is bigger than @h.key
|
||||||
|
h.rbRight = ns.rbDeleteNode(h.rbRight, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rbFixup(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) deleteNode(key uint64) {
|
||||||
|
ns.rbRoot = ns.rbDeleteNode(ns.rbRoot, key)
|
||||||
|
if ns.rbRoot != nil {
|
||||||
|
ns.rbRoot.rbBlack = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) rbIterateNodes(h *lruNode, pivot uint64, iter func(n *lruNode) bool) bool {
|
||||||
|
if h == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if h.key >= pivot {
|
||||||
|
if !ns.rbIterateNodes(h.rbLeft, pivot, iter) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !iter(h) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ns.rbIterateNodes(h.rbRight, pivot, iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *lruNs) iterateNodes(iter func(n *lruNode) bool) {
|
||||||
|
ns.rbIterateNodes(ns.rbRoot, 0, iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *lruNs) Get(key uint64, setf SetFunc) Handle {
|
func (ns *lruNs) Get(key uint64, setf SetFunc) Handle {
|
||||||
ns.lru.mu.Lock()
|
ns.lru.mu.Lock()
|
||||||
|
defer ns.lru.mu.Unlock()
|
||||||
|
|
||||||
if ns.state != nsEffective {
|
if ns.state != nsEffective {
|
||||||
ns.lru.mu.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
node, ok := ns.table[key]
|
var n *lruNode
|
||||||
if ok {
|
if setf == nil {
|
||||||
switch node.state {
|
n = ns.getNode(key)
|
||||||
case nodeEvicted:
|
if n == nil {
|
||||||
// Insert to recent list.
|
|
||||||
node.state = nodeEffective
|
|
||||||
node.ref++
|
|
||||||
ns.lru.used += node.charge
|
|
||||||
ns.lru.evict()
|
|
||||||
fallthrough
|
|
||||||
case nodeEffective:
|
|
||||||
// Bump to front.
|
|
||||||
node.rRemove()
|
|
||||||
node.rInsert(&ns.lru.recent)
|
|
||||||
}
|
|
||||||
node.ref++
|
|
||||||
} else {
|
|
||||||
if setf == nil {
|
|
||||||
ns.lru.mu.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
n = ns.getOrCreateNode(key)
|
||||||
|
}
|
||||||
|
switch n.state {
|
||||||
|
case nodeZero:
|
||||||
charge, value := setf()
|
charge, value := setf()
|
||||||
if value == nil {
|
if value == nil {
|
||||||
ns.lru.mu.Unlock()
|
ns.deleteNode(key)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if charge < 0 {
|
||||||
node = &lruNode{
|
charge = 0
|
||||||
ns: ns,
|
|
||||||
key: key,
|
|
||||||
value: value,
|
|
||||||
charge: charge,
|
|
||||||
ref: 1,
|
|
||||||
}
|
}
|
||||||
ns.table[key] = node
|
|
||||||
|
n.value = value
|
||||||
|
n.charge = charge
|
||||||
|
n.state = nodeEvicted
|
||||||
|
|
||||||
ns.lru.size += charge
|
ns.lru.size += charge
|
||||||
ns.lru.alive++
|
ns.lru.alive++
|
||||||
if charge > 0 {
|
|
||||||
node.ref++
|
|
||||||
node.rInsert(&ns.lru.recent)
|
|
||||||
ns.lru.used += charge
|
|
||||||
ns.lru.evict()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ns.lru.mu.Unlock()
|
fallthrough
|
||||||
return &lruHandle{node: node}
|
case nodeEvicted:
|
||||||
|
if n.charge == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert to recent list.
|
||||||
|
n.state = nodeEffective
|
||||||
|
n.ref++
|
||||||
|
ns.lru.used += n.charge
|
||||||
|
ns.lru.evict()
|
||||||
|
|
||||||
|
fallthrough
|
||||||
|
case nodeEffective:
|
||||||
|
// Bump to front.
|
||||||
|
n.rRemove()
|
||||||
|
n.rInsert(&ns.lru.recent)
|
||||||
|
}
|
||||||
|
n.ref++
|
||||||
|
|
||||||
|
return &lruHandle{node: n}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *lruNs) Delete(key uint64, fin DelFin) bool {
|
func (ns *lruNs) Delete(key uint64, fin DelFin) bool {
|
||||||
ns.lru.mu.Lock()
|
ns.lru.mu.Lock()
|
||||||
|
defer ns.lru.mu.Unlock()
|
||||||
|
|
||||||
if ns.state != nsEffective {
|
if ns.state != nsEffective {
|
||||||
if fin != nil {
|
if fin != nil {
|
||||||
fin(false, false)
|
fin(false, false)
|
||||||
}
|
}
|
||||||
ns.lru.mu.Unlock()
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
node, exist := ns.table[key]
|
n := ns.getNode(key)
|
||||||
if !exist {
|
if n == nil {
|
||||||
if fin != nil {
|
if fin != nil {
|
||||||
fin(false, false)
|
fin(false, false)
|
||||||
}
|
}
|
||||||
ns.lru.mu.Unlock()
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch node.state {
|
switch n.state {
|
||||||
|
case nodeEffective:
|
||||||
|
ns.lru.used -= n.charge
|
||||||
|
n.state = nodeDeleted
|
||||||
|
n.delfin = fin
|
||||||
|
n.rRemove()
|
||||||
|
n.derefNB()
|
||||||
|
case nodeEvicted:
|
||||||
|
n.state = nodeDeleted
|
||||||
|
n.delfin = fin
|
||||||
case nodeDeleted:
|
case nodeDeleted:
|
||||||
if fin != nil {
|
if fin != nil {
|
||||||
fin(true, true)
|
fin(true, true)
|
||||||
}
|
}
|
||||||
ns.lru.mu.Unlock()
|
|
||||||
return false
|
return false
|
||||||
case nodeEffective:
|
|
||||||
ns.lru.used -= node.charge
|
|
||||||
node.state = nodeDeleted
|
|
||||||
node.delfin = fin
|
|
||||||
node.rRemove()
|
|
||||||
node.derefNB()
|
|
||||||
default:
|
default:
|
||||||
node.state = nodeDeleted
|
panic("invalid state")
|
||||||
node.delfin = fin
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ns.lru.mu.Unlock()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *lruNs) purgeNB(fin PurgeFin) {
|
func (ns *lruNs) purgeNB(fin PurgeFin) {
|
||||||
if ns.state != nsEffective {
|
if ns.state == nsEffective {
|
||||||
return
|
var nodes []*lruNode
|
||||||
}
|
ns.iterateNodes(func(n *lruNode) bool {
|
||||||
|
nodes = append(nodes, n)
|
||||||
for _, node := range ns.table {
|
return true
|
||||||
switch node.state {
|
})
|
||||||
case nodeDeleted:
|
for _, n := range nodes {
|
||||||
case nodeEffective:
|
switch n.state {
|
||||||
ns.lru.used -= node.charge
|
case nodeEffective:
|
||||||
node.state = nodeDeleted
|
ns.lru.used -= n.charge
|
||||||
node.purgefin = fin
|
n.state = nodeDeleted
|
||||||
node.rRemove()
|
n.purgefin = fin
|
||||||
node.derefNB()
|
n.rRemove()
|
||||||
default:
|
n.derefNB()
|
||||||
node.state = nodeDeleted
|
case nodeEvicted:
|
||||||
node.purgefin = fin
|
n.state = nodeDeleted
|
||||||
|
n.purgefin = fin
|
||||||
|
case nodeDeleted:
|
||||||
|
default:
|
||||||
|
panic("invalid state")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,22 +405,22 @@ func (ns *lruNs) Purge(fin PurgeFin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ns *lruNs) zapNB() {
|
func (ns *lruNs) zapNB() {
|
||||||
if ns.state != nsEffective {
|
if ns.state == nsEffective {
|
||||||
return
|
ns.state = nsZapped
|
||||||
}
|
|
||||||
|
|
||||||
ns.state = nsZapped
|
ns.iterateNodes(func(n *lruNode) bool {
|
||||||
|
if n.state == nodeEffective {
|
||||||
|
ns.lru.used -= n.charge
|
||||||
|
n.rRemove()
|
||||||
|
}
|
||||||
|
ns.lru.size -= n.charge
|
||||||
|
n.state = nodeDeleted
|
||||||
|
n.fin()
|
||||||
|
|
||||||
for _, node := range ns.table {
|
return true
|
||||||
if node.state == nodeEffective {
|
})
|
||||||
ns.lru.used -= node.charge
|
ns.rbRoot = nil
|
||||||
node.rRemove()
|
|
||||||
}
|
|
||||||
ns.lru.size -= node.charge
|
|
||||||
node.state = nodeDeleted
|
|
||||||
node.fin()
|
|
||||||
}
|
}
|
||||||
ns.table = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *lruNs) Zap() {
|
func (ns *lruNs) Zap() {
|
||||||
@ -293,7 +433,9 @@ func (ns *lruNs) Zap() {
|
|||||||
type lruNode struct {
|
type lruNode struct {
|
||||||
ns *lruNs
|
ns *lruNs
|
||||||
|
|
||||||
rNext, rPrev *lruNode
|
rNext, rPrev *lruNode
|
||||||
|
rbLeft, rbRight *lruNode
|
||||||
|
rbBlack bool
|
||||||
|
|
||||||
key uint64
|
key uint64
|
||||||
value interface{}
|
value interface{}
|
||||||
@ -344,7 +486,7 @@ func (n *lruNode) derefNB() {
|
|||||||
if n.ref == 0 {
|
if n.ref == 0 {
|
||||||
if n.ns.state == nsEffective {
|
if n.ns.state == nsEffective {
|
||||||
// Remove elemement.
|
// Remove elemement.
|
||||||
delete(n.ns.table, n.key)
|
n.ns.deleteNode(n.key)
|
||||||
n.ns.lru.size -= n.charge
|
n.ns.lru.size -= n.charge
|
||||||
n.ns.lru.alive--
|
n.ns.lru.alive--
|
||||||
n.fin()
|
n.fin()
|
||||||
@ -380,3 +522,92 @@ func (h *lruHandle) Release() {
|
|||||||
h.node.deref()
|
h.node.deref()
|
||||||
h.node = nil
|
h.node = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rbIsRed(h *lruNode) bool {
|
||||||
|
if h == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !h.rbBlack
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbRotLeft(h *lruNode) *lruNode {
|
||||||
|
x := h.rbRight
|
||||||
|
if x.rbBlack {
|
||||||
|
panic("rotating a black link")
|
||||||
|
}
|
||||||
|
h.rbRight = x.rbLeft
|
||||||
|
x.rbLeft = h
|
||||||
|
x.rbBlack = h.rbBlack
|
||||||
|
h.rbBlack = false
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbRotRight(h *lruNode) *lruNode {
|
||||||
|
x := h.rbLeft
|
||||||
|
if x.rbBlack {
|
||||||
|
panic("rotating a black link")
|
||||||
|
}
|
||||||
|
h.rbLeft = x.rbRight
|
||||||
|
x.rbRight = h
|
||||||
|
x.rbBlack = h.rbBlack
|
||||||
|
h.rbBlack = false
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbFlip(h *lruNode) {
|
||||||
|
h.rbBlack = !h.rbBlack
|
||||||
|
h.rbLeft.rbBlack = !h.rbLeft.rbBlack
|
||||||
|
h.rbRight.rbBlack = !h.rbRight.rbBlack
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbMoveLeft(h *lruNode) *lruNode {
|
||||||
|
rbFlip(h)
|
||||||
|
if rbIsRed(h.rbRight.rbLeft) {
|
||||||
|
h.rbRight = rbRotRight(h.rbRight)
|
||||||
|
h = rbRotLeft(h)
|
||||||
|
rbFlip(h)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbMoveRight(h *lruNode) *lruNode {
|
||||||
|
rbFlip(h)
|
||||||
|
if rbIsRed(h.rbLeft.rbLeft) {
|
||||||
|
h = rbRotRight(h)
|
||||||
|
rbFlip(h)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbFixup(h *lruNode) *lruNode {
|
||||||
|
if rbIsRed(h.rbRight) {
|
||||||
|
h = rbRotLeft(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rbIsRed(h.rbLeft) && rbIsRed(h.rbLeft.rbLeft) {
|
||||||
|
h = rbRotRight(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rbIsRed(h.rbLeft) && rbIsRed(h.rbRight) {
|
||||||
|
rbFlip(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func rbDeleteMin(h *lruNode) (hn, n *lruNode) {
|
||||||
|
if h == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if h.rbLeft == nil {
|
||||||
|
return nil, h
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rbIsRed(h.rbLeft) && !rbIsRed(h.rbLeft.rbLeft) {
|
||||||
|
h = rbMoveLeft(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.rbLeft, n = rbDeleteMin(h.rbLeft)
|
||||||
|
|
||||||
|
return rbFixup(h), n
|
||||||
|
}
|
||||||
|
2
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go
generated
vendored
@ -1210,7 +1210,7 @@ func TestDb_DeletionMarkers2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDb_CompactionTableOpenError(t *testing.T) {
|
func TestDb_CompactionTableOpenError(t *testing.T) {
|
||||||
h := newDbHarnessWopt(t, &opt.Options{MaxOpenFiles: 0})
|
h := newDbHarnessWopt(t, &opt.Options{CachedOpenFiles: -1})
|
||||||
defer h.close()
|
defer h.close()
|
||||||
|
|
||||||
im := 10
|
im := 10
|
||||||
|
2
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go
generated
vendored
@ -21,7 +21,7 @@ var _ = testutil.Defer(func() {
|
|||||||
BlockRestartInterval: 5,
|
BlockRestartInterval: 5,
|
||||||
BlockSize: 50,
|
BlockSize: 50,
|
||||||
Compression: opt.NoCompression,
|
Compression: opt.NoCompression,
|
||||||
MaxOpenFiles: 0,
|
CachedOpenFiles: -1,
|
||||||
Strict: opt.StrictAll,
|
Strict: opt.StrictAll,
|
||||||
WriteBuffer: 1000,
|
WriteBuffer: 1000,
|
||||||
}
|
}
|
||||||
|
32
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go
generated
vendored
32
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go
generated
vendored
@ -24,7 +24,7 @@ const (
|
|||||||
DefaultBlockRestartInterval = 16
|
DefaultBlockRestartInterval = 16
|
||||||
DefaultBlockSize = 4 * KiB
|
DefaultBlockSize = 4 * KiB
|
||||||
DefaultCompressionType = SnappyCompression
|
DefaultCompressionType = SnappyCompression
|
||||||
DefaultMaxOpenFiles = 1000
|
DefaultCachedOpenFiles = 500
|
||||||
DefaultWriteBuffer = 4 * MiB
|
DefaultWriteBuffer = 4 * MiB
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -125,6 +125,13 @@ type Options struct {
|
|||||||
// The default value is 4KiB.
|
// The default value is 4KiB.
|
||||||
BlockSize int
|
BlockSize int
|
||||||
|
|
||||||
|
// CachedOpenFiles defines number of open files to kept around when not
|
||||||
|
// in-use, the counting includes still in-use files.
|
||||||
|
// Set this to negative value to disable caching.
|
||||||
|
//
|
||||||
|
// The default value is 500.
|
||||||
|
CachedOpenFiles int
|
||||||
|
|
||||||
// Comparer defines a total ordering over the space of []byte keys: a 'less
|
// Comparer defines a total ordering over the space of []byte keys: a 'less
|
||||||
// than' relationship. The same comparison algorithm must be used for reads
|
// than' relationship. The same comparison algorithm must be used for reads
|
||||||
// and writes over the lifetime of the DB.
|
// and writes over the lifetime of the DB.
|
||||||
@ -165,13 +172,6 @@ type Options struct {
|
|||||||
// The default value is nil.
|
// The default value is nil.
|
||||||
Filter filter.Filter
|
Filter filter.Filter
|
||||||
|
|
||||||
// MaxOpenFiles defines maximum number of open files to kept around
|
|
||||||
// (cached). This is not an hard limit, actual open files may exceed
|
|
||||||
// the defined value.
|
|
||||||
//
|
|
||||||
// The default value is 1000.
|
|
||||||
MaxOpenFiles int
|
|
||||||
|
|
||||||
// Strict defines the DB strict level.
|
// Strict defines the DB strict level.
|
||||||
Strict Strict
|
Strict Strict
|
||||||
|
|
||||||
@ -213,6 +213,15 @@ func (o *Options) GetBlockSize() int {
|
|||||||
return o.BlockSize
|
return o.BlockSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Options) GetCachedOpenFiles() int {
|
||||||
|
if o == nil || o.CachedOpenFiles == 0 {
|
||||||
|
return DefaultCachedOpenFiles
|
||||||
|
} else if o.CachedOpenFiles < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return o.CachedOpenFiles
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Options) GetComparer() comparer.Comparer {
|
func (o *Options) GetComparer() comparer.Comparer {
|
||||||
if o == nil || o.Comparer == nil {
|
if o == nil || o.Comparer == nil {
|
||||||
return comparer.DefaultComparer
|
return comparer.DefaultComparer
|
||||||
@ -248,13 +257,6 @@ func (o *Options) GetFilter() filter.Filter {
|
|||||||
return o.Filter
|
return o.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Options) GetMaxOpenFiles() int {
|
|
||||||
if o == nil || o.MaxOpenFiles <= 0 {
|
|
||||||
return DefaultMaxOpenFiles
|
|
||||||
}
|
|
||||||
return o.MaxOpenFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Options) GetStrict(strict Strict) bool {
|
func (o *Options) GetStrict(strict Strict) bool {
|
||||||
if o == nil || o.Strict == 0 {
|
if o == nil || o.Strict == 0 {
|
||||||
return DefaultStrict&strict != 0
|
return DefaultStrict&strict != 0
|
||||||
|
2
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go
generated
vendored
2
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go
generated
vendored
@ -58,7 +58,7 @@ func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) {
|
|||||||
storLock: storLock,
|
storLock: storLock,
|
||||||
}
|
}
|
||||||
s.setOptions(o)
|
s.setOptions(o)
|
||||||
s.tops = newTableOps(s, s.o.GetMaxOpenFiles())
|
s.tops = newTableOps(s, s.o.GetCachedOpenFiles())
|
||||||
s.setVersion(&version{s: s})
|
s.setVersion(&version{s: s})
|
||||||
s.log("log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock D·DeletedEntry L·Level Q·SeqNum T·TimeElapsed")
|
s.log("log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock D·DeletedEntry L·Level Q·SeqNum T·TimeElapsed")
|
||||||
return
|
return
|
||||||
|
1
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go
generated
vendored
1
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go
generated
vendored
@ -25,6 +25,7 @@ func BytesPrefix(prefix []byte) *Range {
|
|||||||
limit = make([]byte, i+1)
|
limit = make([]byte, i+1)
|
||||||
copy(limit, prefix)
|
copy(limit, prefix)
|
||||||
limit[i] = c + 1
|
limit[i] = c + 1
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Range{prefix, limit}
|
return &Range{prefix, limit}
|
||||||
|
@ -391,7 +391,7 @@ func syncthingMain() {
|
|||||||
// If this is the first time the user runs v0.9, archive the old indexes and config.
|
// If this is the first time the user runs v0.9, archive the old indexes and config.
|
||||||
archiveLegacyConfig()
|
archiveLegacyConfig()
|
||||||
|
|
||||||
db, err := leveldb.OpenFile(filepath.Join(confDir, "index"), &opt.Options{MaxOpenFiles: 100})
|
db, err := leveldb.OpenFile(filepath.Join(confDir, "index"), &opt.Options{CachedOpenFiles: 100})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Fatalln("Cannot open database:", err, "- Is another copy of Syncthing already running?")
|
l.Fatalln("Cannot open database:", err, "- Is another copy of Syncthing already running?")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user