1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2015 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #include "config.h"
19 
20 #include "objectregistry.h"
21 
22 #include "ep_engine.h"
23 #include "item.h"
24 #include "stored-value.h"
25 #include "threadlocal.h"
26 
27 #if 1
28 static ThreadLocal<EventuallyPersistentEngine*> *th;
29 static ThreadLocal<std::atomic<size_t>*> *initial_track;
30 
31 extern "C" {
defaultGetAllocSize(const void *)32     static size_t defaultGetAllocSize(const void *) {
33         return 0;
34     }
35 }
36 
37 static get_allocation_size getAllocSize = defaultGetAllocSize;
38 
39 
40 
41 /**
42  * Object registry link hook for getting the registry thread local
43  * installed.
44  */
45 class installer {
46 public:
installer()47    installer() {
48       if (th == NULL) {
49          th = new ThreadLocal<EventuallyPersistentEngine*>();
50          initial_track = new ThreadLocal<std::atomic<size_t>*>();
51       }
52    }
53 
~installer()54    ~installer() {
55        delete initial_track;
56        delete th;
57    }
58 } install;
59 
verifyEngine(EventuallyPersistentEngine *engine)60 static bool verifyEngine(EventuallyPersistentEngine *engine)
61 {
62    if (engine == NULL) {
63        if (getenv("ALLOW_NO_STATS_UPDATE") != NULL) {
64            return false;
65        } else {
66            throw std::logic_error("verifyEngine: engine should be non-NULL");
67        }
68    }
69    return true;
70 }
71 
initialize(get_allocation_size func)72 void ObjectRegistry::initialize(get_allocation_size func) {
73     getAllocSize = func;
74 }
75 
reset()76 void ObjectRegistry::reset() {
77     getAllocSize = defaultGetAllocSize;
78 }
79 
onCreateBlob(const Blob *blob)80 void ObjectRegistry::onCreateBlob(const Blob *blob)
81 {
82    EventuallyPersistentEngine *engine = th->get();
83    if (verifyEngine(engine)) {
84        auto& coreLocalStats = engine->getEpStats().coreLocal.get();
85 
86        size_t size = getAllocSize(blob);
87        if (size == 0) {
88            size = blob->getSize();
89        } else {
90            coreLocalStats->blobOverhead.fetch_add(size - blob->getSize());
91        }
92        coreLocalStats->currentSize.fetch_add(size);
93        coreLocalStats->totalValueSize.fetch_add(size);
94        coreLocalStats->numBlob++;
95    }
96 }
97 
onDeleteBlob(const Blob *blob)98 void ObjectRegistry::onDeleteBlob(const Blob *blob)
99 {
100    EventuallyPersistentEngine *engine = th->get();
101    if (verifyEngine(engine)) {
102        auto& coreLocalStats = engine->getEpStats().coreLocal.get();
103 
104        size_t size = getAllocSize(blob);
105        if (size == 0) {
106            size = blob->getSize();
107        } else {
108            coreLocalStats->blobOverhead.fetch_sub(size - blob->getSize());
109        }
110        coreLocalStats->currentSize.fetch_sub(size);
111        coreLocalStats->totalValueSize.fetch_sub(size);
112        coreLocalStats->numBlob--;
113    }
114 }
115 
onCreateStoredValue(const StoredValue *sv)116 void ObjectRegistry::onCreateStoredValue(const StoredValue *sv)
117 {
118    EventuallyPersistentEngine *engine = th->get();
119    if (verifyEngine(engine)) {
120        auto& coreLocalStats = engine->getEpStats().coreLocal.get();
121 
122        size_t size = getAllocSize(sv);
123        if (size == 0) {
124            size = sv->getObjectSize();
125        } else {
126            coreLocalStats->storedValOverhead.fetch_add(size -
127                                                        sv->getObjectSize());
128        }
129        coreLocalStats->numStoredVal++;
130        coreLocalStats->totalStoredValSize.fetch_add(size);
131    }
132 }
133 
onDeleteStoredValue(const StoredValue *sv)134 void ObjectRegistry::onDeleteStoredValue(const StoredValue *sv)
135 {
136    EventuallyPersistentEngine *engine = th->get();
137    if (verifyEngine(engine)) {
138        auto& coreLocalStats = engine->getEpStats().coreLocal.get();
139 
140        size_t size = getAllocSize(sv);
141        if (size == 0) {
142            size = sv->getObjectSize();
143        } else {
144            coreLocalStats->storedValOverhead.fetch_sub(size -
145                                                        sv->getObjectSize());
146        }
147        coreLocalStats->totalStoredValSize.fetch_sub(size);
148        coreLocalStats->numStoredVal--;
149    }
150 }
151 
152 
onCreateItem(const Item *pItem)153 void ObjectRegistry::onCreateItem(const Item *pItem)
154 {
155    EventuallyPersistentEngine *engine = th->get();
156    if (verifyEngine(engine)) {
157        auto& coreLocalStats = engine->getEpStats().coreLocal.get();
158        coreLocalStats->memOverhead.fetch_add(pItem->size() -
159                                              pItem->getValMemSize());
160        ++coreLocalStats->numItem;
161    }
162 }
163 
onDeleteItem(const Item *pItem)164 void ObjectRegistry::onDeleteItem(const Item *pItem)
165 {
166    EventuallyPersistentEngine *engine = th->get();
167    if (verifyEngine(engine)) {
168        auto& coreLocalStats = engine->getEpStats().coreLocal.get();
169        coreLocalStats->memOverhead.fetch_sub(pItem->size() -
170                                              pItem->getValMemSize());
171        --coreLocalStats->numItem;
172    }
173 }
174 
getCurrentEngine()175 EventuallyPersistentEngine *ObjectRegistry::getCurrentEngine() {
176     return th->get();
177 }
178 
onSwitchThread( EventuallyPersistentEngine *engine, bool want_old_thread_local)179 EventuallyPersistentEngine *ObjectRegistry::onSwitchThread(
180                                             EventuallyPersistentEngine *engine,
181                                             bool want_old_thread_local) {
182     EventuallyPersistentEngine *old_engine = NULL;
183 
184     if (want_old_thread_local) {
185         old_engine = th->get();
186     }
187 
188     th->set(engine);
189     return old_engine;
190 }
191 
setStats(std::atomic<size_t>* init_track)192 void ObjectRegistry::setStats(std::atomic<size_t>* init_track) {
193     initial_track->set(init_track);
194 }
195 
memoryAllocated(size_t mem)196 bool ObjectRegistry::memoryAllocated(size_t mem) {
197     EventuallyPersistentEngine *engine = th->get();
198     if (initial_track->get()) {
199         initial_track->get()->fetch_add(mem);
200     }
201     if (!engine) {
202         return false;
203     }
204     EPStats &stats = engine->getEpStats();
205     stats.memAllocated(mem);
206     return true;
207 }
208 
memoryDeallocated(size_t mem)209 bool ObjectRegistry::memoryDeallocated(size_t mem) {
210     EventuallyPersistentEngine *engine = th->get();
211     if (initial_track->get()) {
212         initial_track->get()->fetch_sub(mem);
213     }
214     if (!engine) {
215         return false;
216     }
217     EPStats &stats = engine->getEpStats();
218     stats.memDeallocated(mem);
219     return true;
220 }
221 
SystemAllocationGuard()222 SystemAllocationGuard::SystemAllocationGuard() {
223     engine = th->get();
224     th->set(nullptr);
225 }
226 
~SystemAllocationGuard()227 SystemAllocationGuard::~SystemAllocationGuard() {
228     th->set(engine);
229 }
230 
231 #endif
232