diff options
author | Harald Musum <musum@verizonmedia.com> | 2020-08-24 14:08:53 +0200 |
---|---|---|
committer | Harald Musum <musum@verizonmedia.com> | 2020-08-24 14:08:53 +0200 |
commit | 55b2cbc1e8c9b06dd128fde8bd1a348226aaba1f (patch) | |
tree | a468d457310d34df2525570ec4a8a65161b73fa1 /configserver | |
parent | 799f23ff147c17a79cd9164c99925bafca9486c8 (diff) |
Add timestamp for creating of tenant to TenantMetaData
Diffstat (limited to 'configserver')
4 files changed, 82 insertions, 24 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java index 137d0f1889e..73120e90a3e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java @@ -25,7 +25,6 @@ import com.yahoo.io.IOUtils; import com.yahoo.jdisc.Metric; import com.yahoo.path.Path; import com.yahoo.slime.Slime; -import com.yahoo.text.Utf8; import com.yahoo.transaction.NestedTransaction; import com.yahoo.transaction.Transaction; import com.yahoo.vespa.config.server.application.Application; @@ -65,8 +64,6 @@ import com.yahoo.vespa.config.server.tenant.TenantMetaData; import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.curator.Lock; -import com.yahoo.vespa.curator.transaction.CuratorOperations; -import com.yahoo.vespa.curator.transaction.CuratorTransaction; import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.flags.BooleanFlag; import com.yahoo.vespa.flags.FlagSource; @@ -415,24 +412,18 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } if (useTenantMetaData.value()) - transaction.add(writeTenantMetaData(tenant).operations()); + transaction.add(updateMetaDataWithDeployTimestamp(tenant, clock.instant())); return transaction; } - private byte[] createMetaData(Tenant tenant) { - return new TenantMetaData(tenant.getSessionRepository().clock().instant()).asJsonBytes(); + private List<Transaction.Operation> updateMetaDataWithDeployTimestamp(Tenant tenant, Instant deployTimestamp) { + TenantMetaData tenantMetaData = getTenantMetaData(tenant).withLastDeployTimestamp(deployTimestamp); + return tenantRepository.createWriteTenantMetaDataTransaction(tenantMetaData).operations(); } TenantMetaData getTenantMetaData(Tenant tenant) { - Optional<byte[]> data = tenantRepository.getCurator().getData(TenantRepository.getTenantPath(tenant.getName())); - return data.map(bytes -> TenantMetaData.fromJsonString(Utf8.toString(bytes))).orElse(new TenantMetaData(tenant.getCreatedTime())); - } - - private Transaction writeTenantMetaData(Tenant tenant) { - return new CuratorTransaction(tenantRepository.getCurator()) - .add(CuratorOperations.setData(TenantRepository.getTenantPath(tenant.getName()).getAbsolute(), - createMetaData(tenant))); + return tenantRepository.getTenantMetaData(tenant); } static void checkIfActiveHasChanged(LocalSession session, Session currentActiveSession, boolean ignoreStaleSessionFailure) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantMetaData.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantMetaData.java index 24862b82fb0..b8db47e371f 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantMetaData.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantMetaData.java @@ -1,30 +1,50 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server.tenant; +import com.yahoo.config.provision.TenantName; import com.yahoo.slime.Cursor; import com.yahoo.slime.Inspector; import com.yahoo.slime.Slime; import com.yahoo.slime.SlimeUtils; +import com.yahoo.text.Utf8; import java.io.IOException; import java.time.Instant; /** - * Metadata for a tenant. At the moment only stores last deploy time, to be used by TenantsMaintainer - * to GC unused tenants + * Meta data for a tenant like tenant name, tenant creation time and last deployment time, stored in ZooKeeper * * @author hmusum */ public class TenantMetaData { - private final Instant lastDeployTimestamp; + private static final String createTimestampKey = "createTimestampKey"; + private static final String lastDeployTimestampKey = "lastDeployTimestamp"; - public TenantMetaData(Instant instant) { - this.lastDeployTimestamp = instant; + private final TenantName tenantName; + private final Instant created; + private final Instant lastDeployed; + + public TenantMetaData(TenantName tenantName, Instant lastDeployed, Instant created) { + this.tenantName = tenantName; + this.created = created; + this.lastDeployed = lastDeployed; + } + + public TenantMetaData withLastDeployTimestamp(Instant deployTimestamp) { + return new TenantMetaData(tenantName, deployTimestamp, created); + } + + public TenantName tenantName() { + return tenantName; } public Instant lastDeployTimestamp() { - return lastDeployTimestamp; + return lastDeployed; + } + + public Instant createdTimestamp() { + return created; } public byte[] asJsonBytes() { @@ -35,13 +55,16 @@ public class TenantMetaData { } } - public static TenantMetaData fromJsonString(String jsonString) { + public static TenantMetaData fromJsonString(TenantName tenantName, String jsonString) { try { Slime data = SlimeUtils.jsonToSlime(jsonString); Inspector root = data.get(); - Inspector lastDeployTimestamp = root.field("lastDeployTimestamp"); + Inspector created = root.field(createTimestampKey); + Inspector lastDeployTimestamp = root.field(lastDeployTimestampKey); - return new TenantMetaData(Instant.ofEpochMilli(lastDeployTimestamp.asLong())); + return new TenantMetaData(tenantName, + Instant.ofEpochMilli(lastDeployTimestamp.asLong()), + Instant.ofEpochMilli(created.asLong())); } catch (Exception e) { throw new IllegalArgumentException("Error parsing json metadata", e); } @@ -50,8 +73,14 @@ public class TenantMetaData { private Slime getSlime() { Slime slime = new Slime(); Cursor meta = slime.setObject(); - meta.setLong("lastDeployTimestamp", lastDeployTimestamp.toEpochMilli()); + meta.setLong(createTimestampKey, created.toEpochMilli()); + meta.setLong(lastDeployTimestampKey, lastDeployed.toEpochMilli()); return slime; } + @Override + public String toString() { + return tenantName + ": " + Utf8.toString(asJsonBytes()); + } + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java index d6e3c6905fb..2f05b7e7fe8 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java @@ -8,12 +8,18 @@ import com.yahoo.concurrent.StripedExecutor; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.TenantName; import com.yahoo.path.Path; +import com.yahoo.text.Utf8; +import com.yahoo.transaction.Transaction; import com.yahoo.vespa.config.server.GlobalComponentRegistry; import com.yahoo.vespa.config.server.application.TenantApplications; import com.yahoo.vespa.config.server.deploy.TenantFileSystemDirs; import com.yahoo.vespa.config.server.monitoring.MetricUpdater; import com.yahoo.vespa.config.server.session.SessionRepository; import com.yahoo.vespa.curator.Curator; +import com.yahoo.vespa.curator.transaction.CuratorOperations; +import com.yahoo.vespa.curator.transaction.CuratorTransaction; +import com.yahoo.vespa.flags.BooleanFlag; +import com.yahoo.vespa.flags.Flags; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.apache.curator.framework.state.ConnectionState; @@ -82,6 +88,7 @@ public class TenantRepository { private final ExecutorService bootstrapExecutor; private final ScheduledExecutorService checkForRemovedApplicationsService = new ScheduledThreadPoolExecutor(1); private final Optional<Curator.DirectoryCache> directoryCache; + private final BooleanFlag useTenantMetaData; /** * Creates a new tenant repository @@ -109,6 +116,7 @@ public class TenantRepository { this.tenantListeners.add(componentRegistry.getTenantListener()); this.zkCacheExecutor = componentRegistry.getZkCacheExecutor(); this.zkWatcherExecutor = componentRegistry.getZkWatcherExecutor(); + this.useTenantMetaData = Flags.USE_TENANT_META_DATA.bindTo(componentRegistry.getFlagSource()); curator.framework().getConnectionStateListenable().addListener(this::stateChanged); curator.create(tenantsPath); @@ -142,6 +150,30 @@ public class TenantRepository { createTenant(tenantName, componentRegistry.getClock().instant()); } + public void createAndWriteTenantMetaData(Tenant tenant) { + createWriteTenantMetaDataTransaction(createMetaData(tenant)).commit(); + } + + public Transaction createWriteTenantMetaDataTransaction(TenantMetaData tenantMetaData) { + return new CuratorTransaction(curator).add( + CuratorOperations.setData(TenantRepository.getTenantPath(tenantMetaData.tenantName()).getAbsolute(), + tenantMetaData.asJsonBytes())); + } + + private TenantMetaData createMetaData(Tenant tenant) { + Instant deployTime = tenant.getSessionRepository().clock().instant(); + Instant createdTime = getTenantMetaData(tenant).createdTimestamp(); + if (createdTime.equals(Instant.EPOCH)) + createdTime = deployTime; + return new TenantMetaData(tenant.getName(), deployTime, createdTime); + } + + public TenantMetaData getTenantMetaData(Tenant tenant) { + Optional<byte[]> data = getCurator().getData(TenantRepository.getTenantPath(tenant.getName())); + return data.map(bytes -> TenantMetaData.fromJsonString(tenant.getName(), Utf8.toString(bytes))) + .orElse(new TenantMetaData(tenant.getName(), tenant.getCreatedTime(), tenant.getCreatedTime())); + } + private static Set<TenantName> readTenantsFromZooKeeper(Curator curator) { return curator.getChildren(tenantsPath).stream().map(TenantName::from).collect(Collectors.toSet()); } @@ -226,6 +258,8 @@ public class TenantRepository { Tenant tenant = new Tenant(tenantName, sessionRepository, applicationRepo, applicationRepo, created); notifyNewTenant(tenant); tenants.putIfAbsent(tenantName, tenant); + if (useTenantMetaData.value()) + createAndWriteTenantMetaData(tenant); } /** diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java index beac308cf77..cb43e80e82d 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java @@ -167,6 +167,7 @@ public class ApplicationRepositoryTest { session.getAllocatedHosts(); assertEquals(Instant.EPOCH, applicationRepository.getTenantMetaData(tenant).lastDeployTimestamp()); + assertEquals(Instant.EPOCH, applicationRepository.getTenantMetaData(tenant).createdTimestamp()); } @Test @@ -174,6 +175,7 @@ public class ApplicationRepositoryTest { FlagSource flagSource = new InMemoryFlagSource().withBooleanFlag(Flags.USE_TENANT_META_DATA.id(), true); setup(flagSource); + Instant startTime = clock.instant(); Duration duration = Duration.ofHours(1); clock.advance(duration); Instant deployTime = clock.instant(); @@ -188,6 +190,8 @@ public class ApplicationRepositoryTest { assertEquals(deployTime.toEpochMilli(), applicationRepository.getTenantMetaData(tenant).lastDeployTimestamp().toEpochMilli()); + assertEquals(startTime.toEpochMilli(), + applicationRepository.getTenantMetaData(tenant).createdTimestamp().toEpochMilli()); } @Test |