Use a memoizing supplier instead of a looping thread to cache remote config entries

This commit is contained in:
Jon Chambers 2021-11-24 17:45:33 -05:00 committed by Chris Eager
parent d89b4f7e95
commit 048e17c62b
3 changed files with 10 additions and 63 deletions

View File

@ -593,7 +593,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
environment.lifecycle().manage(accountDatabaseCrawler); environment.lifecycle().manage(accountDatabaseCrawler);
environment.lifecycle().manage(directoryReconciliationAccountDatabaseCrawler); environment.lifecycle().manage(directoryReconciliationAccountDatabaseCrawler);
environment.lifecycle().manage(deletedAccountsTableCrawler); environment.lifecycle().manage(deletedAccountsTableCrawler);
environment.lifecycle().manage(remoteConfigsManager);
environment.lifecycle().manage(messagesCache); environment.lifecycle().manage(messagesCache);
environment.lifecycle().manage(messagePersister); environment.lifecycle().manage(messagePersister);
environment.lifecycle().manage(clientPresenceManager); environment.lifecycle().manage(clientPresenceManager);

View File

@ -5,70 +5,26 @@
package org.whispersystems.textsecuregcm.storage; package org.whispersystems.textsecuregcm.storage;
import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers;
import io.dropwizard.lifecycle.Managed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.util.Util;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier;
public class RemoteConfigsManager implements Managed { public class RemoteConfigsManager {
private final Logger logger = LoggerFactory.getLogger(RemoteConfigsManager.class);
private final RemoteConfigs remoteConfigs; private final RemoteConfigs remoteConfigs;
private final long sleepInterval;
private final AtomicReference<List<RemoteConfig>> cachedConfigs = new AtomicReference<>(new LinkedList<>()); private final Supplier<List<RemoteConfig>> remoteConfigSupplier;
public RemoteConfigsManager(RemoteConfigs remoteConfigs) { public RemoteConfigsManager(RemoteConfigs remoteConfigs) {
this(remoteConfigs, TimeUnit.SECONDS.toMillis(10));
}
@VisibleForTesting
public RemoteConfigsManager(RemoteConfigs remoteConfigs, long sleepInterval) {
this.remoteConfigs = remoteConfigs; this.remoteConfigs = remoteConfigs;
this.sleepInterval = sleepInterval;
}
@Override remoteConfigSupplier =
public void start() { Suppliers.memoizeWithExpiration(remoteConfigs::getAll, 10, TimeUnit.SECONDS);
refreshCache();
new Thread(() -> {
while (true) {
try {
refreshCache();
} catch (Throwable t) {
logger.warn("Error updating remote configs cache", t);
}
Util.sleep(sleepInterval);
}
}).start();
}
private void refreshCache() {
this.cachedConfigs.set(remoteConfigs.getAll());
synchronized (this.cachedConfigs) {
this.cachedConfigs.notifyAll();
}
}
@VisibleForTesting
void waitForCacheRefresh() throws InterruptedException {
synchronized (this.cachedConfigs) {
this.cachedConfigs.wait();
}
} }
public List<RemoteConfig> getAll() { public List<RemoteConfig> getAll() {
return cachedConfigs.get(); return remoteConfigSupplier.get();
} }
public void set(RemoteConfig config) { public void set(RemoteConfig config) {
@ -78,9 +34,4 @@ public class RemoteConfigsManager implements Managed {
public void delete(String name) { public void delete(String name) {
remoteConfigs.delete(name); remoteConfigs.delete(name);
} }
@Override
public void stop() throws Exception {
}
} }

View File

@ -29,21 +29,18 @@ public class RemoteConfigsManagerTest {
@Before @Before
public void setup() { public void setup() {
RemoteConfigs remoteConfigs = new RemoteConfigs(new FaultTolerantDatabase("remote_configs-test", Jdbi.create(db.getTestDatabase()), new CircuitBreakerConfiguration())); this.remoteConfigs = new RemoteConfigsManager(new RemoteConfigs(
this.remoteConfigs = new RemoteConfigsManager(remoteConfigs, 500); new FaultTolerantDatabase("remote_configs-test", Jdbi.create(db.getTestDatabase()), new CircuitBreakerConfiguration())));
this.remoteConfigs.start();
} }
@Test @Test
public void testUpdate() throws InterruptedException { public void testUpdate() {
remoteConfigs.set(new RemoteConfig("android.stickers", 50, Set.of(AuthHelper.VALID_UUID), "FALSE", "TRUE", null)); remoteConfigs.set(new RemoteConfig("android.stickers", 50, Set.of(AuthHelper.VALID_UUID), "FALSE", "TRUE", null));
remoteConfigs.set(new RemoteConfig("value.sometimes", 50, Set.of(), "bar", "baz", null)); remoteConfigs.set(new RemoteConfig("value.sometimes", 50, Set.of(), "bar", "baz", null));
remoteConfigs.set(new RemoteConfig("ios.stickers", 50, Set.of(), "FALSE", "TRUE", null)); remoteConfigs.set(new RemoteConfig("ios.stickers", 50, Set.of(), "FALSE", "TRUE", null));
remoteConfigs.set(new RemoteConfig("ios.stickers", 75, Set.of(), "FALSE", "TRUE", null)); remoteConfigs.set(new RemoteConfig("ios.stickers", 75, Set.of(), "FALSE", "TRUE", null));
remoteConfigs.set(new RemoteConfig("value.sometimes", 25, Set.of(AuthHelper.VALID_UUID), "abc", "def", null)); remoteConfigs.set(new RemoteConfig("value.sometimes", 25, Set.of(AuthHelper.VALID_UUID), "abc", "def", null));
remoteConfigs.waitForCacheRefresh();
List<RemoteConfig> results = remoteConfigs.getAll(); List<RemoteConfig> results = remoteConfigs.getAll();
assertThat(results.size()).isEqualTo(3); assertThat(results.size()).isEqualTo(3);