cubefs

Форк
0
/
extent_cache.go 
167 строк · 4.0 Кб
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 storage
16

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

22
// ExtentMapItem stores the extent entity pointer and the element
23
// pointer of the extent entity in a cache list.
24
type ExtentMapItem struct {
25
	e       *Extent
26
	element *list.Element
27
}
28

29
// ExtentCache is an implementation of the ExtentCache with LRU support.
30
type ExtentCache struct {
31
	extentMap   map[uint64]*ExtentMapItem
32
	extentList  *list.List
33
	tinyExtents map[uint64]*Extent
34
	tinyLock    sync.RWMutex
35
	lock        sync.RWMutex
36
	capacity    int
37
}
38

39
// NewExtentCache creates and returns a new ExtentCache instance.
40
func NewExtentCache(capacity int) *ExtentCache {
41
	return &ExtentCache{
42
		extentMap:   make(map[uint64]*ExtentMapItem),
43
		extentList:  list.New(),
44
		capacity:    capacity,
45
		tinyExtents: make(map[uint64]*Extent),
46
	}
47
}
48

49
// Put puts an extent object into the cache.
50
func (cache *ExtentCache) Put(e *Extent) {
51
	if IsTinyExtent(e.extentID) {
52
		cache.tinyLock.Lock()
53
		cache.tinyExtents[e.extentID] = e
54
		cache.tinyLock.Unlock()
55
		return
56
	}
57
	cache.lock.Lock()
58
	defer cache.lock.Unlock()
59
	item := &ExtentMapItem{
60
		e:       e,
61
		element: cache.extentList.PushBack(e),
62
	}
63
	cache.extentMap[e.extentID] = item
64
	cache.evict()
65
}
66

67
// Get gets the extent from the cache.
68
func (cache *ExtentCache) Get(extentID uint64) (e *Extent, ok bool) {
69
	if IsTinyExtent(extentID) {
70
		cache.tinyLock.RLock()
71
		e, ok = cache.tinyExtents[extentID]
72
		cache.tinyLock.RUnlock()
73
		return
74
	}
75
	cache.lock.Lock()
76
	defer cache.lock.Unlock()
77
	var item *ExtentMapItem
78
	if item, ok = cache.extentMap[extentID]; ok {
79
		if !IsTinyExtent(extentID) {
80
			cache.extentList.MoveToBack(item.element)
81
		}
82
		e = item.e
83
	}
84
	return
85
}
86

87
// Del deletes the extent stored in the cache.
88
func (cache *ExtentCache) Del(extentID uint64) {
89
	if IsTinyExtent(extentID) {
90
		return
91
	}
92
	cache.lock.Lock()
93
	defer cache.lock.Unlock()
94
	var (
95
		item *ExtentMapItem
96
		ok   bool
97
	)
98
	if item, ok = cache.extentMap[extentID]; ok {
99
		delete(cache.extentMap, extentID)
100
		cache.extentList.Remove(item.element)
101

102
		item.e.Close()
103
	}
104
}
105

106
// Clear closes all the extents stored in the cache.
107
func (cache *ExtentCache) Clear() {
108
	cache.tinyLock.RLock()
109
	for _, extent := range cache.tinyExtents {
110
		extent.Close()
111
	}
112
	cache.tinyLock.RUnlock()
113

114
	cache.lock.Lock()
115
	defer cache.lock.Unlock()
116
	for e := cache.extentList.Front(); e != nil; {
117
		curr := e
118
		e = e.Next()
119
		ec := curr.Value.(*Extent)
120
		delete(cache.extentMap, ec.extentID)
121

122
		ec.Close()
123
		cache.extentList.Remove(curr)
124
	}
125
	cache.extentList = list.New()
126
	cache.extentMap = make(map[uint64]*ExtentMapItem)
127
}
128

129
// Size returns number of extents stored in the cache.
130
func (cache *ExtentCache) Size() int {
131
	cache.lock.RLock()
132
	defer cache.lock.RUnlock()
133
	return cache.extentList.Len()
134
}
135

136
func (cache *ExtentCache) evict() {
137
	if cache.capacity <= 0 {
138
		return
139
	}
140
	needRemove := cache.extentList.Len() - cache.capacity
141
	for i := 0; i < needRemove; i++ {
142
		if e := cache.extentList.Front(); e != nil {
143
			front := e.Value.(*Extent)
144
			if IsTinyExtent(front.extentID) {
145
				continue
146
			}
147
			delete(cache.extentMap, front.extentID)
148
			cache.extentList.Remove(e)
149
			front.Close()
150
		}
151
	}
152
}
153

154
// Flush synchronizes the extent stored in the cache to the disk.
155
func (cache *ExtentCache) Flush() {
156
	cache.tinyLock.RLock()
157
	for _, extent := range cache.tinyExtents {
158
		extent.Flush()
159
	}
160
	cache.tinyLock.RUnlock()
161

162
	cache.lock.RLock()
163
	defer cache.lock.RUnlock()
164
	for _, item := range cache.extentMap {
165
		item.e.Flush()
166
	}
167
}
168

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

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

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

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