Browse code

[core] BM-11670 Try: cache directory entries to speed up IContainers.get() (and others). Speed goes from 242/sec to 644/sec in unit test.

Thomas Cataldo authored on 22/06/2017 12:43:40
Showing 6 changed files
... ...
@@ -31,6 +31,7 @@ Require-Bundle: net.bluemind.core.rest,
31 31
  net.bluemind.role.api,
32 32
  net.bluemind.core.sanitizer,
33 33
  net.bluemind.core.validator,
34
- net.bluemind.core.annotationvalidator
34
+ net.bluemind.core.annotationvalidator,
35
+ net.bluemind.core.caches.registry
35 36
 Export-Package: net.bluemind.directory.service,
36 37
  net.bluemind.directory.service.internal
... ...
@@ -25,5 +25,11 @@
25 25
       <validatorfactory
26 26
             implementation="net.bluemind.directory.service.internal.OrgUnitValidatorFactory"></validatorfactory>
27 27
    </extension>
28
+   <extension
29
+         point="net.bluemind.core.caches.registry.registration">
30
+      <reg
31
+            impl="net.bluemind.directory.service.internal.DirEntriesCache">
32
+      </reg>
33
+   </extension>
28 34
 
29 35
 </plugin>
... ...
@@ -40,6 +40,7 @@ import net.bluemind.core.context.SecurityContext;
40 40
 import net.bluemind.directory.api.DirEntry;
41 41
 import net.bluemind.directory.persistance.DirEntryStore;
42 42
 import net.bluemind.directory.persistance.DirItemStore;
43
+import net.bluemind.directory.service.internal.DirEntriesCache;
43 44
 import net.bluemind.document.storage.DocumentStorage;
44 45
 import net.bluemind.document.storage.IDocumentStore;
45 46
 import net.bluemind.domain.api.Domain;
... ...
@@ -174,6 +175,7 @@ public abstract class DirValueStoreService<T> extends ContainerStoreService<DirE
174 175
 	}
175 176
 
176 177
 	public void update(String uid, DirEntry dirEntry, T value) throws ServerFault {
178
+		DirEntriesCache.get(container.domainUid).invalidate(uid);
177 179
 		create(uid, dirEntry.displayName, new DirEntryAndValue<>(dirEntry, value,
178 180
 				vcardAdapter.asVCard(domain, uid, value), asMailbox(container.domainUid, uid, value)));
179 181
 	}
... ...
@@ -193,6 +195,7 @@ public abstract class DirValueStoreService<T> extends ContainerStoreService<DirE
193 195
 
194 196
 	public void update(String uid, T value) throws ServerFault {
195 197
 		DirEntry dirEntry = adapter.asDirEntry(container.domainUid, uid, value);
198
+		DirEntriesCache.get(container.domainUid).invalidate(uid);
196 199
 		update(uid, dirEntry.displayName, new DirEntryAndValue<>(dirEntry, value,
197 200
 				vcardAdapter.asVCard(domain, uid, value), asMailbox(container.domainUid, uid, value)));
198 201
 	}
... ...
@@ -318,4 +321,16 @@ public abstract class DirValueStoreService<T> extends ContainerStoreService<DirE
318 321
 		return "dir_" + container.uid + "/icons/" + uid;
319 322
 	}
320 323
 
324
+	@Override
325
+	public boolean delete(String uid) throws ServerFault {
326
+		DirEntriesCache.get(container.domainUid).invalidate(uid);
327
+		return super.delete(uid);
328
+	}
329
+
330
+	@Override
331
+	public void deleteAll() throws ServerFault {
332
+		DirEntriesCache.get(container.domainUid).invalidateAll();
333
+		super.deleteAll();
334
+	}
335
+
321 336
 }
322 337
new file mode 100644
... ...
@@ -0,0 +1,88 @@
1
+/* BEGIN LICENSE
2
+  * Copyright © Blue Mind SAS, 2012-2017
3
+  *
4
+  * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+  * solution.
6
+  *
7
+  * This program is free software; you can redistribute it and/or modify
8
+  * it under the terms of either the GNU Affero General Public License as
9
+  * published by the Free Software Foundation (version 3 of the License).
10
+  *
11
+  * This program is distributed in the hope that it will be useful,
12
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
+  *
15
+  * See LICENSE.txt
16
+  * END LICENSE
17
+  */
18
+package net.bluemind.directory.service.internal;
19
+
20
+import java.util.concurrent.TimeUnit;
21
+import java.util.function.Supplier;
22
+
23
+import org.slf4j.Logger;
24
+import org.slf4j.LoggerFactory;
25
+
26
+import com.google.common.cache.Cache;
27
+import com.google.common.cache.CacheBuilder;
28
+
29
+import net.bluemind.core.caches.registry.CacheRegistry;
30
+import net.bluemind.core.caches.registry.ICacheRegistration;
31
+import net.bluemind.core.container.model.ItemValue;
32
+import net.bluemind.directory.api.DirEntry;
33
+
34
+public class DirEntriesCache implements ICacheRegistration {
35
+
36
+	private static final Cache<String, ItemValue<DirEntry>> dirCache = CacheBuilder.newBuilder()
37
+			.expireAfterAccess(1, TimeUnit.MINUTES).build();
38
+	private static final Logger logger = LoggerFactory.getLogger(DirEntriesCache.class);
39
+
40
+	private final String domainUid;
41
+
42
+	public DirEntriesCache() {
43
+		this("global.virt");
44
+	}
45
+
46
+	public DirEntriesCache(String domainUid) {
47
+		this.domainUid = domainUid;
48
+	}
49
+
50
+	public static DirEntriesCache get(String domainUid) {
51
+		return new DirEntriesCache(domainUid);
52
+	}
53
+
54
+	private String key(String uid) {
55
+		return uid + "@" + domainUid;
56
+	}
57
+
58
+	public ItemValue<DirEntry> get(String uid, Supplier<ItemValue<DirEntry>> de) {
59
+		String key = key(uid);
60
+		ItemValue<DirEntry> ret = dirCache.getIfPresent(key);
61
+		if (ret == null) {
62
+			ret = de.get();
63
+			if (ret != null) {
64
+				dirCache.put(key, ret);
65
+			}
66
+		}
67
+		return ret;
68
+	}
69
+
70
+	public void cache(ItemValue<DirEntry> item) {
71
+		dirCache.put(key(item.uid), item);
72
+	}
73
+
74
+	public void invalidate(String uid) {
75
+		dirCache.invalidate(key(uid));
76
+	}
77
+
78
+	@Override
79
+	public void registerCaches(CacheRegistry cr) {
80
+		logger.info("Registered DirEntries cache");
81
+		cr.register(dirCache);
82
+	}
83
+
84
+	public void invalidateAll() {
85
+		dirCache.invalidateAll();
86
+	}
87
+
88
+}
... ...
@@ -49,6 +49,7 @@ public class DirEntryStoreService extends ContainerStoreService<DirEntry> {
49 49
 	private VCardStore vcardStore;
50 50
 	private IDocumentStore documentStore;
51 51
 	private OrgUnitStore ouStore;
52
+	private final String domainUid;
52 53
 
53 54
 	public DirEntryStoreService(BmContext context, Container container, String domainUid) {
54 55
 		super(context.getDataSource(), context.getSecurityContext(), container, "dir",
... ...
@@ -56,6 +57,7 @@ public class DirEntryStoreService extends ContainerStoreService<DirEntry> {
56 57
 		this.ouStore = new OrgUnitStore(context.getDataSource(), container);
57 58
 		this.entryStore = new DirEntryStore(context.getDataSource(), container);
58 59
 		this.vcardStore = new VCardStore(context.getDataSource(), container);
60
+		this.domainUid = domainUid;
59 61
 		documentStore = DocumentStorage.store;
60 62
 	}
61 63
 
... ...
@@ -162,4 +164,22 @@ public class DirEntryStoreService extends ContainerStoreService<DirEntry> {
162 164
 		}
163 165
 	}
164 166
 
167
+	@Override
168
+	public long update(String uid, String displayName, DirEntry value) throws ServerFault {
169
+		DirEntriesCache.get(domainUid).invalidate(uid);
170
+		return super.update(uid, displayName, value);
171
+	}
172
+
173
+	@Override
174
+	public boolean delete(String uid) throws ServerFault {
175
+		DirEntriesCache.get(domainUid).invalidate(uid);
176
+		return super.delete(uid);
177
+	}
178
+
179
+	@Override
180
+	public void deleteAll() throws ServerFault {
181
+		DirEntriesCache.get(domainUid).invalidateAll();
182
+		super.deleteAll();
183
+	}
184
+
165 185
 }
... ...
@@ -88,7 +88,8 @@ public class Directory implements IDirectory {
88 88
 	@Override
89 89
 	public DirEntry findByEntryUid(String entryUid) throws ServerFault {
90 90
 		checkReadAccess();
91
-		ItemValue<DirEntry> itemValue = itemStore.get(entryUid, null);
91
+		ItemValue<DirEntry> itemValue = DirEntriesCache.get(domainUid).get(entryUid,
92
+				() -> itemStore.get(entryUid, null));
92 93
 		if (itemValue != null && itemValue.value != null) {
93 94
 			return translate(itemValue).value;
94 95
 		} else {
... ...
@@ -153,7 +154,6 @@ public class Directory implements IDirectory {
153 154
 		if (dir == null) {
154 155
 			throw new ServerFault("entry " + entryUid + " doesnt exists", ErrorCode.NOT_FOUND);
155 156
 		}
156
-
157 157
 		DirEntryHandler handler = DirEntryHandlers.byKind(dir.value.kind);
158 158
 
159 159
 		handler.entryDeleted(context, domainUid, dir.value.entryUid);