cubefs

Форк
0
/
icache.go 
172 строки · 4.6 Кб
1
// Copyright 2018 The CubeFS Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
// implied. See the License for the specific language governing
13
// permissions and limitations under the License.
14

15
package fs
16

17
import (
18
	"container/list"
19
	"sync"
20
	"time"
21

22
	"github.com/cubefs/cubefs/proto"
23
	"github.com/cubefs/cubefs/util/log"
24
)
25

26
const (
27
	// MinInodeCacheEvictNum is used in the foreground eviction.
28
	// When clearing the inodes from the cache, it stops as soon as 10 inodes have been evicted.
29
	MinInodeCacheEvictNum = 10
30
	// MaxInodeCacheEvictNum is used in the back ground. We can evict 200000 inodes at max.
31
	MaxInodeCacheEvictNum = 200000
32

33
	BgEvictionInterval = 2 * time.Minute
34
)
35

36
// InodeCache defines the structure of the inode cache.
37
type InodeCache struct {
38
	sync.RWMutex
39
	cache       map[uint64]*list.Element
40
	lruList     *list.List
41
	expiration  time.Duration
42
	maxElements int
43
}
44

45
// NewInodeCache returns a new inode cache.
46
func NewInodeCache(exp time.Duration, maxElements int) *InodeCache {
47
	ic := &InodeCache{
48
		cache:       make(map[uint64]*list.Element),
49
		lruList:     list.New(),
50
		expiration:  exp,
51
		maxElements: maxElements,
52
	}
53
	go ic.backgroundEviction()
54
	return ic
55
}
56

57
// Put puts the given inode info into the inode cache.
58
func (ic *InodeCache) Put(info *proto.InodeInfo) {
59
	ic.Lock()
60
	old, ok := ic.cache[info.Inode]
61
	if ok {
62
		ic.lruList.Remove(old)
63
		delete(ic.cache, info.Inode)
64
	}
65

66
	if ic.lruList.Len() >= ic.maxElements {
67
		ic.evict(true)
68
	}
69

70
	inodeSetExpiration(info, ic.expiration)
71
	element := ic.lruList.PushFront(info)
72
	ic.cache[info.Inode] = element
73
	ic.Unlock()
74
	// log.LogDebugf("InodeCache put inode: inode(%v)", info.Inode)
75
}
76

77
// Get returns the inode info based on the given inode number.
78
func (ic *InodeCache) Get(ino uint64) *proto.InodeInfo {
79
	ic.RLock()
80
	element, ok := ic.cache[ino]
81
	if !ok {
82
		ic.RUnlock()
83
		return nil
84
	}
85

86
	info := element.Value.(*proto.InodeInfo)
87
	if inodeExpired(info) && DisableMetaCache {
88
		ic.RUnlock()
89
		// log.LogDebugf("InodeCache GetConnect expired: now(%v) inode(%v), expired(%d)", time.Now().Format(LogTimeFormat), info.Inode, info.Expiration())
90
		return nil
91
	}
92
	ic.RUnlock()
93
	return info
94
}
95

96
// Delete deletes the inode info based on the given inode number.
97
func (ic *InodeCache) Delete(ino uint64) {
98
	// log.LogDebugf("InodeCache Delete: ino(%v)", ino)
99
	ic.Lock()
100
	element, ok := ic.cache[ino]
101
	if ok {
102
		ic.lruList.Remove(element)
103
		delete(ic.cache, ino)
104
	}
105
	ic.Unlock()
106
}
107

108
// Foreground eviction cares more about the speed.
109
// Background eviction evicts all expired items from the cache.
110
// The caller should grab the WRITE lock of the inode cache.
111
func (ic *InodeCache) evict(foreground bool) {
112
	var count int
113

114
	for i := 0; i < MinInodeCacheEvictNum; i++ {
115
		element := ic.lruList.Back()
116
		if element == nil {
117
			return
118
		}
119

120
		// For background eviction, if all expired items have been evicted, just return
121
		// But for foreground eviction, we need to evict at least MinInodeCacheEvictNum inodes.
122
		// The foreground eviction, does not need to care if the inode has expired or not.
123
		info := element.Value.(*proto.InodeInfo)
124
		if !foreground && !inodeExpired(info) {
125
			return
126
		}
127

128
		// log.LogDebugf("InodeCache GetConnect expired: now(%v) inode(%v)", time.Now().Format(LogTimeFormat), info.Inode)
129
		ic.lruList.Remove(element)
130
		delete(ic.cache, info.Inode)
131
		count++
132
	}
133

134
	// For background eviction, we need to continue evict all expired items from the cache
135
	if foreground {
136
		return
137
	}
138

139
	for i := 0; i < MaxInodeCacheEvictNum; i++ {
140
		element := ic.lruList.Back()
141
		if element == nil {
142
			break
143
		}
144
		info := element.Value.(*proto.InodeInfo)
145
		if !inodeExpired(info) {
146
			break
147
		}
148
		// log.LogDebugf("InodeCache GetConnect expired: now(%v) inode(%v)", time.Now().Format(LogTimeFormat), info.Inode)
149
		ic.lruList.Remove(element)
150
		delete(ic.cache, info.Inode)
151
		count++
152
	}
153
}
154

155
func (ic *InodeCache) backgroundEviction() {
156
	t := time.NewTicker(BgEvictionInterval)
157
	defer t.Stop()
158

159
	for range t.C {
160
		log.LogInfof("InodeCache: start BG evict")
161
		if !DisableMetaCache {
162
			log.LogInfof("InodeCache: no need to do BG evict")
163
			continue
164
		}
165
		start := time.Now()
166
		ic.Lock()
167
		ic.evict(false)
168
		ic.Unlock()
169
		elapsed := time.Since(start)
170
		log.LogInfof("InodeCache: total inode cache(%d), cost(%d)ns", ic.lruList.Len(), elapsed.Nanoseconds())
171
	}
172
}
173

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.