Browse code

[perf] ACMS-261 Fix: cache AclStore results as they are high in yourkit profiles

Thomas Cataldo authored on 10/01/2018 11:37:51
Showing 17 changed files
... ...
@@ -118,7 +118,8 @@ public abstract class AbstractServiceTests {
118 118
 
119 119
 		vCardStore = new VCardStore(JdbcTestHelper.getInstance().getDataSource(), container);
120 120
 		tagRefStore = new TagRefStore(JdbcTestHelper.getInstance().getDataSource(), container);
121
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
121
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
122
+				JdbcTestHelper.getInstance().getDataSource());
122 123
 		aclStore.store(container,
123 124
 				Arrays.asList(AccessControlEntry.create(defaultSecurityContext.getSubject(), Verb.All)));
124 125
 
... ...
@@ -152,7 +153,8 @@ public abstract class AbstractServiceTests {
152 152
 		String containerId = "tags_" + userUid;
153 153
 		tagContainer = Container.create(containerId, TagsContainerType.TYPE, "test", userUid, "global.virt", true);
154 154
 		tagContainer = containerHome.create(tagContainer);
155
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
155
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
156
+				JdbcTestHelper.getInstance().getDataSource());
156 157
 		aclStore.store(tagContainer,
157 158
 				Arrays.asList(AccessControlEntry.create(defaultSecurityContext.getSubject(), Verb.All)));
158 159
 
... ...
@@ -69,6 +69,7 @@ import net.bluemind.core.elasticsearch.ElasticsearchTestHelper;
69 69
 import net.bluemind.core.jdbc.JdbcTestHelper;
70 70
 import net.bluemind.core.rest.LocalJsonObject;
71 71
 import net.bluemind.core.rest.ServerSideServiceProvider;
72
+import net.bluemind.core.tests.BmTestContext;
72 73
 import net.bluemind.core.tests.vertx.VertxEventChecker;
73 74
 import net.bluemind.tag.api.ITags;
74 75
 import net.bluemind.tag.api.TagRef;
... ...
@@ -442,7 +443,8 @@ public class AddressBookServiceTests extends AbstractServiceTests {
442 442
 		String uid3 = create(defaultVCard());
443 443
 
444 444
 		Container container2 = createTestContainer("not_mine");
445
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
445
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
446
+				JdbcTestHelper.getInstance().getDataSource());
446 447
 		aclStore.store(container2,
447 448
 				Arrays.asList(AccessControlEntry.create(defaultSecurityContext.getSubject(), Verb.All)));
448 449
 
... ...
@@ -482,7 +484,8 @@ public class AddressBookServiceTests extends AbstractServiceTests {
482 482
 		String uid3 = create(defaultVCard());
483 483
 
484 484
 		Container container2 = createTestContainer("not_mine");
485
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
485
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
486
+				JdbcTestHelper.getInstance().getDataSource());
486 487
 		aclStore.store(container2,
487 488
 				Arrays.asList(AccessControlEntry.create(defaultSecurityContext.getSubject(), Verb.All)));
488 489
 
... ...
@@ -308,7 +308,8 @@ public abstract class AbstractCalendarTests {
308 308
 		group.emails = groupMailbox.emails;
309 309
 
310 310
 		// Acls
311
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
311
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
312
+				JdbcTestHelper.getInstance().getDataSource());
312 313
 		List<AccessControlEntry> ace = Arrays
313 314
 				.asList(AccessControlEntry.create(userSecurityContext.getSubject(), Verb.All));
314 315
 		aclStore.store(domainContainer, ace);
... ...
@@ -118,7 +118,8 @@ public class CalendarAutocompleteServiceTests {
118 118
 
119 119
 		containerStore = new ContainerStore(JdbcTestHelper.getInstance().getDataSource(), defaultSecurityContext);
120 120
 
121
-		aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
121
+		aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
122
+				JdbcTestHelper.getInstance().getDataSource());
122 123
 
123 124
 		Container container = Container.create("addressbook_testUser", "addressbook", "Contacts",
124 125
 				defaultSecurityContext.getSubject(), "bm.lan", true);
... ...
@@ -263,13 +263,13 @@ public class CalendarServiceTests extends AbstractCalendarTests {
263 263
 		} catch (ServerFault e) {
264 264
 			assertEquals(ErrorCode.PERMISSION_DENIED, e.getCode());
265 265
 		}
266
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
266
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
267
+				JdbcTestHelper.getInstance().getDataSource());
267 268
 
268 269
 		getCalendarService(userSecurityContext, userCalendarContainer).update(uid, event, sendNotifications);
269 270
 
270 271
 		Message<JsonObject> message = updatedMessageChecker.shouldSuccess();
271 272
 		assertNotNull(message);
272
-		
273 273
 
274 274
 		List<AccessControlEntry> ace = Arrays.asList(
275 275
 				AccessControlEntry.create(userSecurityContext.getSubject(), Verb.All),
... ...
@@ -281,13 +281,13 @@ public class CalendarServiceTests extends AbstractCalendarTests {
281 281
 			e.printStackTrace();
282 282
 		}
283 283
 		try {
284
-			//Cannot modifiy private event with write verb
284
+			// Cannot modifiy private event with write verb
285 285
 			getCalendarService(attendee2SecurityContext, userCalendarContainer).update(uid, event, sendNotifications);
286 286
 			fail();
287 287
 		} catch (ServerFault e) {
288 288
 			assertEquals(ErrorCode.PERMISSION_DENIED, e.getCode());
289 289
 		}
290
-		//Can modifiy private event with manage verb
290
+		// Can modifiy private event with manage verb
291 291
 
292 292
 		getCalendarService(attendee1SecurityContext, userCalendarContainer).update(uid, event, sendNotifications);
293 293
 
... ...
@@ -60,7 +60,8 @@ public class PublishCalendarTests extends AbstractCalendarTests {
60 60
 		} catch (ServerFault sf) {
61 61
 		}
62 62
 
63
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
63
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
64
+				JdbcTestHelper.getInstance().getDataSource());
64 65
 		List<AccessControlEntry> ace = Arrays
65 66
 				.asList(AccessControlEntry.create(basicUserSecurityContext.getSubject(), Verb.Read));
66 67
 		aclStore.store(userCalendarContainer, ace);
... ...
@@ -98,7 +99,8 @@ public class PublishCalendarTests extends AbstractCalendarTests {
98 98
 		}
99 99
 
100 100
 		String token = "123soleil";
101
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
101
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
102
+				JdbcTestHelper.getInstance().getDataSource());
102 103
 		List<AccessControlEntry> ace = Arrays.asList(AccessControlEntry.create(token, Verb.Read));
103 104
 		aclStore.store(userCalendarContainer, ace);
104 105
 
... ...
@@ -310,7 +310,8 @@ public class VFreebusyServiceTests extends AbstractCalendarTests {
310 310
 			assertEquals(ErrorCode.PERMISSION_DENIED, e.getCode());
311 311
 		}
312 312
 
313
-		AclStore aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
313
+		AclStore aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
314
+				JdbcTestHelper.getInstance().getDataSource());
314 315
 		aclStore.store(userFreebusyContainer,
315 316
 				Arrays.asList(AccessControlEntry.create(attendee1SecurityContext.getSubject(), Verb.Read)));
316 317
 
... ...
@@ -459,7 +460,8 @@ public class VFreebusyServiceTests extends AbstractCalendarTests {
459 459
 
460 460
 		assertEquals(dtstart, new BmDateTimeWrapper(freebusy.dtstart).toJodaTime());
461 461
 		assertEquals(dtend, new BmDateTimeWrapper(freebusy.dtend).toJodaTime());
462
-		// 2 busy-unavailable slot by work week day + 1 busy-unavalable by week-end day + 1 busy per month
462
+		// 2 busy-unavailable slot by work week day + 1 busy-unavalable by
463
+		// week-end day + 1 busy per month
463 464
 		// 52 * 5 * 2 + 52 * 2 + 12
464 465
 		assertEquals(636, freebusy.slots.size());
465 466
 
... ...
@@ -475,13 +477,15 @@ public class VFreebusyServiceTests extends AbstractCalendarTests {
475 475
 
476 476
 		freebusy = getVFreebusyService(userSecurityContext, userFreebusyContainer)
477 477
 				.get(VFreebusyQuery.create(time(dtstart, false), time(dtend, false)));
478
-		// 2 busy-unavailable slot by work week day + 1 busy-unavalable by week-end day + 1 busy per month
479
-		// 52 * 2 * 2 + 52 * 5 + 12	
478
+		// 2 busy-unavailable slot by work week day + 1 busy-unavalable by
479
+		// week-end day + 1 busy per month
480
+		// 52 * 2 * 2 + 52 * 5 + 12
480 481
 		assertEquals(480, freebusy.slots.size());
481
-		for(Slot s: freebusy.slots) {
482
-			if (s.type.equals(VFreebusy.Type.BUSYUNAVAILABLE) && s.dtstart.iso8601.equals("2014-01-06T00:00:00.000+01:00")) {
482
+		for (Slot s : freebusy.slots) {
483
+			if (s.type.equals(VFreebusy.Type.BUSYUNAVAILABLE)
484
+					&& s.dtstart.iso8601.equals("2014-01-06T00:00:00.000+01:00")) {
483 485
 				assertEquals(s.dtend.iso8601, "2014-01-06T04:00:00.000+01:00");
484
-				return ;
486
+				return;
485 487
 			}
486 488
 		}
487 489
 		fail("Fail to match the first monday as busy-unavailable");
... ...
@@ -7,5 +7,10 @@
7 7
             impl="net.bluemind.core.container.persistance.ContainerCache$Registration">
8 8
       </reg>
9 9
    </extension>
10
-
10
+   <extension
11
+         point="net.bluemind.core.caches.registry.registration">
12
+      <reg
13
+            impl="net.bluemind.core.container.persistance.AclCache$Registration">
14
+      </reg>
15
+   </extension>
11 16
 </plugin>
12 17
new file mode 100644
... ...
@@ -0,0 +1,75 @@
0
+/* BEGIN LICENSE
1
+  * Copyright © Blue Mind SAS, 2012-2018
2
+  *
3
+  * This file is part of BlueMind. BlueMind is a messaging and collaborative
4
+  * solution.
5
+  *
6
+  * This program is free software; you can redistribute it and/or modify
7
+  * it under the terms of either the GNU Affero General Public License as
8
+  * published by the Free Software Foundation (version 3 of the License).
9
+  *
10
+  * This program is distributed in the hope that it will be useful,
11
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+  *
14
+  * See LICENSE.txt
15
+  * END LICENSE
16
+  */
17
+package net.bluemind.core.container.persistance;
18
+
19
+import java.util.List;
20
+
21
+import com.google.common.cache.Cache;
22
+import com.google.common.cache.CacheBuilder;
23
+
24
+import net.bluemind.core.caches.registry.CacheRegistry;
25
+import net.bluemind.core.caches.registry.ICacheRegistration;
26
+import net.bluemind.core.container.model.acl.AccessControlEntry;
27
+import net.bluemind.core.rest.BmContext;
28
+
29
+public class AclCache {
30
+
31
+	public static class Registration implements ICacheRegistration {
32
+
33
+		@Override
34
+		public void registerCaches(CacheRegistry cr) {
35
+			cr.register(AclCache.class, CacheBuilder.newBuilder().build());
36
+		}
37
+	}
38
+
39
+	private final Cache<String, List<AccessControlEntry>> cache;
40
+
41
+	public AclCache(Cache<String, List<AccessControlEntry>> c) {
42
+		this.cache = c;
43
+	}
44
+
45
+	public static AclCache get(BmContext context) {
46
+		if (context == null || context.provider().instance(CacheRegistry.class) == null) {
47
+			return new AclCache(null);
48
+		} else {
49
+			return new AclCache(context.provider().instance(CacheRegistry.class).get(AclCache.class));
50
+		}
51
+	}
52
+
53
+	public List<AccessControlEntry> getIfPresent(String uid) {
54
+		if (cache != null) {
55
+			return cache.getIfPresent(uid);
56
+		} else {
57
+			return null;
58
+		}
59
+
60
+	}
61
+
62
+	public void put(String uid, List<AccessControlEntry> c) {
63
+		if (cache != null) {
64
+			cache.put(uid, c);
65
+		}
66
+	}
67
+
68
+	public void invalidate(String uid) {
69
+		if (cache != null) {
70
+			cache.invalidate(uid);
71
+		}
72
+	}
73
+
74
+}
... ...
@@ -31,9 +31,12 @@ import net.bluemind.core.container.model.Container;
31 31
 import net.bluemind.core.container.model.acl.AccessControlEntry;
32 32
 import net.bluemind.core.container.model.acl.Verb;
33 33
 import net.bluemind.core.jdbc.JdbcAbstractStore;
34
+import net.bluemind.core.rest.BmContext;
34 35
 
35 36
 public class AclStore extends JdbcAbstractStore {
36 37
 
38
+	private AclCache cache;
39
+
37 40
 	private JdbcAbstractStore.StatementValues<AccessControlEntry> statementValues(final int position,
38 41
 			final Container container) {
39 42
 
... ...
@@ -46,8 +49,20 @@ public class AclStore extends JdbcAbstractStore {
46 46
 		};
47 47
 	}
48 48
 
49
+	/**
50
+	 * please prefer the {@link AclStore#AclStore(BmContext, DataSource)}
51
+	 * variant that enables caching.
52
+	 * 
53
+	 * @param pool
54
+	 */
55
+	@Deprecated
49 56
 	public AclStore(DataSource pool) {
57
+		this(null, pool);
58
+	}
59
+
60
+	public AclStore(BmContext ctx, DataSource pool) {
50 61
 		super(pool);
62
+		this.cache = AclCache.get(ctx);
51 63
 	}
52 64
 
53 65
 	public void store(final Container container, final List<AccessControlEntry> entries)
... ...
@@ -56,6 +71,7 @@ public class AclStore extends JdbcAbstractStore {
56 56
 			delete("DELETE FROM t_container_acl where container_id = ?", new Object[] { container.id });
57 57
 			batchInsert("INSERT INTO t_container_acl ( container_id, subject, verb, position) values (?, ?, ?, ?)",
58 58
 					new ArrayList<>(new HashSet<>(entries)), statementValues(0, container));
59
+			cache.put(container.uid, entries);
59 60
 			return null;
60 61
 		});
61 62
 	}
... ...
@@ -64,22 +80,31 @@ public class AclStore extends JdbcAbstractStore {
64 64
 		List<AccessControlEntry> previous = get(container);
65 65
 		batchInsert("INSERT INTO t_container_acl (container_id, subject, verb, position) values (?, ?, ?, ?)", entries,
66 66
 				statementValues(previous.size(), container));
67
+		cache.invalidate(container.uid);
67 68
 	}
68 69
 
70
+	private static final String GET_QUERY = "select subject, verb from t_container_acl where container_id = ?  order by position";
71
+
69 72
 	public List<AccessControlEntry> get(final Container container) throws SQLException {
70
-		String query = "select subject, verb from t_container_acl where container_id = ?  order by position";
71
-		return select(query, (rs) -> new AccessControlEntry(),
72
-				Arrays.<EntityPopulator<AccessControlEntry>> asList((rs, index, value) -> {
73
+		List<AccessControlEntry> cached = cache.getIfPresent(container.uid);
74
+		if (cached != null) {
75
+			return cached;
76
+		}
77
+		List<AccessControlEntry> acls = select(GET_QUERY, (rs) -> new AccessControlEntry(),
78
+				Arrays.<EntityPopulator<AccessControlEntry>>asList((rs, index, value) -> {
73 79
 
74 80
 					String subject = rs.getString(index++);
75 81
 					value.subject = subject;
76 82
 					value.verb = Verb.valueOf(rs.getString(index++));
77 83
 					return index;
78 84
 				}), new Object[] { container.id });
85
+		cache.put(container.uid, acls);
86
+		return acls;
79 87
 	}
80 88
 
81 89
 	public void deleteAll(Container container) throws SQLException {
82 90
 		delete("delete from t_container_acl where container_id  = ? ", new Object[] { container.id });
91
+		cache.invalidate(container.uid);
83 92
 	}
84 93
 
85 94
 	public DataSource getDataSource() {
... ...
@@ -67,6 +67,14 @@ public class ContainerStore extends JdbcAbstractStore {
67 67
 
68 68
 	};
69 69
 
70
+	/**
71
+	 * please prefer the
72
+	 * {@link ContainerStore#ContainerStore(BmContext, DataSource, SecurityContext)}
73
+	 * variant that enables caching.
74
+	 * 
75
+	 * @param dataSource
76
+	 * @param securityContext
77
+	 */
70 78
 	@Deprecated
71 79
 	public ContainerStore(DataSource dataSource, SecurityContext securityContext) {
72 80
 		this(null, dataSource, securityContext);
... ...
@@ -39,6 +39,7 @@ import net.bluemind.core.jdbc.JdbcActivator;
39 39
 import net.bluemind.core.jdbc.JdbcTestHelper;
40 40
 import net.bluemind.core.rest.ServerSideServiceProvider;
41 41
 import net.bluemind.core.sessions.Sessions;
42
+import net.bluemind.core.tests.BmTestContext;
42 43
 import net.bluemind.lib.vertx.VertxPlatform;
43 44
 import net.bluemind.tests.defaultdata.PopulateHelper;
44 45
 import net.bluemind.user.api.IUserSubscription;
... ...
@@ -81,7 +82,8 @@ public class ContainerManagementTests {
81 81
 
82 82
 		itemStore = new ItemStore(JdbcTestHelper.getInstance().getDataSource(), container, SecurityContext.SYSTEM);
83 83
 
84
-		aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
84
+		aclStore = new AclStore(new BmTestContext(SecurityContext.SYSTEM),
85
+				JdbcTestHelper.getInstance().getDataSource());
85 86
 
86 87
 		aclStore.store(container, Arrays.asList(AccessControlEntry.create(testSecurityContext.getSubject(), Verb.All),
87 88
 				AccessControlEntry.create(testGroup, Verb.Write)));
... ...
@@ -68,10 +68,9 @@ public class RBACManagerTests {
68 68
 
69 69
 		userUid = PopulateHelper.addUser("toto", domainUid, Routing.none);
70 70
 		containerStore = new ContainerStore(JdbcTestHelper.getInstance().getDataSource(), SecurityContext.SYSTEM);
71
-
72
-		aclStore = new AclStore(JdbcTestHelper.getInstance().getDataSource());
73 71
 		final SettableFuture<Void> future = SettableFuture.<Void>create();
74 72
 		testContext = new BmTestContext(SecurityContext.SYSTEM);
73
+		aclStore = new AclStore(testContext, JdbcTestHelper.getInstance().getDataSource());
75 74
 		Handler<AsyncResult<Void>> done = new Handler<AsyncResult<Void>>() {
76 75
 
77 76
 			@Override
... ...
@@ -95,7 +95,7 @@ public class ContainerManagement implements IContainerManagement {
95 95
 		containerPersonalSettingsStore = new ContainerPersonalSettingsStore(context.getDataSource(),
96 96
 				context.getSecurityContext(), container);
97 97
 		containerSettingsStore = new ContainerSettingsStore(context.getDataSource(), container);
98
-		aclStore = new AclStore(context.getDataSource());
98
+		aclStore = new AclStore(context, context.getDataSource());
99 99
 
100 100
 		sanitizer = new Sanitizer(context);
101 101
 		validator = new Validator(context);
... ...
@@ -59,7 +59,7 @@ public class ContainerPermissionResolver {
59 59
 		}
60 60
 		List<AccessControlEntry> acl = null;
61 61
 		try {
62
-			acl = new AclStore(context.getDataSource()).get(container);
62
+			acl = new AclStore(context, context.getDataSource()).get(container);
63 63
 		} catch (SQLException e) {
64 64
 			throw ServerFault.sqlFault(e);
65 65
 		}
... ...
@@ -85,7 +85,7 @@ public class Containers implements IContainers {
85 85
 		this.dataSource = context.getDataSource();
86 86
 		this.securityContext = context.getSecurityContext();
87 87
 		containerStore = new ContainerStore(context, this.dataSource, this.securityContext);
88
-		aclStore = new AclStore(context.getDataSource());
88
+		aclStore = new AclStore(context, context.getDataSource());
89 89
 		this.context = context;
90 90
 		sanitizer = new Sanitizer(context);
91 91
 		validator = new Validator(context);
... ...
@@ -181,7 +181,7 @@ public class GroupProtocolHandler implements Handler<Buffer> {
181 181
 				for (String g : groupsAndUser.groups) {
182 182
 					ret.add("group:" + g + "@" + domain);
183 183
 				}
184
-				logger.info("found user {}@{}, memberof {}", login, domain, ret);
184
+				logger.debug("found user {}@{}, memberof {}", login, domain, ret);
185 185
 
186 186
 				String res = String.join(",", ret);
187 187
 				if (!res.isEmpty()) {