Skip to content

Commit e4d1f90

Browse files
authored
Merge pull request #445 from weaviate/v6-tenant
v6: Per-collection-handle tenant
2 parents 3818d0c + b9765b2 commit e4d1f90

File tree

62 files changed

+1858
-272
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1858
-272
lines changed

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@
244244
<artifactId>maven-surefire-plugin</artifactId>
245245
<version>2.22.2</version>
246246
<configuration>
247+
<trimStackTrace>false</trimStackTrace>
247248
<argLine>
248249
<!--
249250
Gson (used for JSON serialization) utilizes reflection and needs to be able to access private fields of

src/it/java/io/weaviate/ConcurrentTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22

33
import java.util.Random;
44
import java.util.UUID;
5+
import java.util.concurrent.Callable;
6+
import java.util.concurrent.CompletableFuture;
7+
import java.util.concurrent.ExecutionException;
8+
import java.util.concurrent.TimeUnit;
9+
import java.util.concurrent.TimeoutException;
510

611
import org.apache.commons.lang3.RandomStringUtils;
12+
import org.assertj.core.api.Assertions;
713
import org.junit.Rule;
814
import org.junit.rules.TestName;
915

@@ -62,4 +68,46 @@ protected static float[] randomVector(int length, float origin, float bound) {
6268
}
6369
return vector;
6470
}
71+
72+
/**
73+
* Check that a condition is eventually met.
74+
*
75+
* @param cond Arbitrary code that evaluates the test condition..
76+
* @param intervalMillis Polling interval.
77+
* @param timeoutSeconds Maximum waiting time.
78+
* @param message Optional failure message.
79+
*
80+
* @throws AssertionError if the condition does not evaluate to true
81+
* within {@code timeoutSeconds} or a thread
82+
* was interrupted in the meantime.
83+
* @throws RuntimeException if an exception occurred when envalating condition.
84+
*/
85+
public static void eventually(Callable<Boolean> cond, int intervalMillis, int timeoutSeconds, String... message) {
86+
var check = CompletableFuture.runAsync(() -> {
87+
try {
88+
while (!Thread.currentThread().isInterrupted() && !cond.call()) {
89+
try {
90+
Thread.sleep(intervalMillis);
91+
} catch (InterruptedException ex) {
92+
Thread.currentThread().interrupt();
93+
}
94+
}
95+
} catch (Exception e) {
96+
// Propagate to callee
97+
throw new RuntimeException(e);
98+
}
99+
});
100+
101+
try {
102+
check.get(timeoutSeconds, TimeUnit.SECONDS);
103+
} catch (TimeoutException ex) {
104+
check.cancel(true);
105+
Assertions.fail(message.length >= 0 ? message[0] : null, ex);
106+
} catch (InterruptedException ex) {
107+
Thread.currentThread().interrupt();
108+
Assertions.fail(ex);
109+
} catch (ExecutionException ex) {
110+
throw new RuntimeException(ex);
111+
}
112+
}
65113
}

src/it/java/io/weaviate/containers/Container.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class Container {
1616
public static final Weaviate WEAVIATE = Weaviate.createDefault();
1717
public static final Contextionary CONTEXTIONARY = Contextionary.createDefault();
1818
public static final Img2VecNeural IMG2VEC_NEURAL = Img2VecNeural.createDefault();
19+
public static final MinIo MINIO = MinIo.createDefault();
1920

2021
static {
2122
startAll();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.weaviate.containers;
2+
3+
import org.testcontainers.containers.MinIOContainer;
4+
5+
public class MinIo extends MinIOContainer {
6+
private static final String DOCKER_IMAGE = "minio/minio";
7+
public static final String ACCESS_KEY = "minioadmin";
8+
public static final String SECRET_KEY = "minioadmin";
9+
10+
static MinIo createDefault() {
11+
return new MinIo();
12+
}
13+
14+
private MinIo() {
15+
super(DOCKER_IMAGE);
16+
withUserName(ACCESS_KEY);
17+
withPassword(SECRET_KEY);
18+
withCreateContainerCmdModifier(cmd -> cmd.withHostName("minio"));
19+
}
20+
}

src/it/java/io/weaviate/containers/Weaviate.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ public Builder withImageInference(String url, String module) {
8989
return this;
9090
}
9191

92+
public Builder withOffloadS3(String accessKey, String secretKey) {
93+
addModules("offload-s3");
94+
environment.put("OFFLOAD_S3_ENDPOINT", "http://minio:9000");
95+
environment.put("OFFLOAD_S3_BUCKET_AUTO_CREATE", "true");
96+
environment.put("AWS_ACCESS_KEY_ID", accessKey);
97+
environment.put("AWS_SECRET_KEY", secretKey);
98+
return this;
99+
}
100+
92101
public Builder enableTelemetry(boolean enable) {
93102
telemetry = enable;
94103
return this;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package io.weaviate.integration;
2+
3+
import org.assertj.core.api.Assertions;
4+
import org.junit.Test;
5+
6+
import io.weaviate.ConcurrentTest;
7+
import io.weaviate.client6.v1.api.WeaviateClient;
8+
import io.weaviate.client6.v1.api.collections.tenants.Tenant;
9+
import io.weaviate.containers.Container;
10+
import io.weaviate.containers.Container.ContainerGroup;
11+
import io.weaviate.containers.MinIo;
12+
import io.weaviate.containers.Weaviate;
13+
14+
public class TenantsITest extends ConcurrentTest {
15+
private static final ContainerGroup compose = Container.compose(
16+
Weaviate.custom()
17+
.withOffloadS3(MinIo.ACCESS_KEY, MinIo.SECRET_KEY)
18+
.build(),
19+
Container.MINIO);
20+
21+
private static WeaviateClient client = compose.getClient();
22+
23+
@Test
24+
public void test_tenantLifecycle() throws Exception {
25+
var nsThings = ns("Things");
26+
27+
client.collections.create(
28+
nsThings, c -> c
29+
.multiTenancy(mt -> mt
30+
.autoTenantCreation(false)
31+
.autoTenantActivation(false)));
32+
33+
var things = client.collections.use(nsThings);
34+
35+
// No tenants at first
36+
Assertions.assertThat(things.tenants.list()).as("no tenants initially").isEmpty();
37+
38+
var allison = Tenant.active("active-allison");
39+
var isaac = Tenant.inactive("inactive-isaac");
40+
var owen = Tenant.inactive("offloaded-owen");
41+
42+
things.tenants.create(allison, isaac, owen);
43+
44+
// Collection has 2 tenants creted just now.
45+
Assertions.assertThat(things.tenants.list()).as("list created tenants").hasSize(3);
46+
Assertions.assertThat(things.tenants.exists(allison.name()))
47+
.describedAs("%s exists", allison.name()).isTrue();
48+
Assertions.assertThat(things.tenants.exists(isaac.name()))
49+
.describedAs("%s exists", isaac.name()).isTrue();
50+
Assertions.assertThat(things.tenants.exists(owen.name()))
51+
.describedAs("%s exists", owen.name()).isTrue();
52+
53+
things.tenants.activate(isaac.name());
54+
eventually(() -> things.tenants.get(isaac.name()).get().isActive(),
55+
200, 2, isaac.name() + " not activated");
56+
57+
things.tenants.deactivate(allison.name());
58+
eventually(() -> things.tenants.get(allison.name()).get().isInactive(),
59+
200, 2, allison.name() + " not deactivated");
60+
61+
things.tenants.offload(owen.name());
62+
eventually(() -> things.tenants.get(owen.name()).get().isOffloaded(),
63+
200, 2, owen.name() + " not offloaded");
64+
65+
things.tenants.delete(allison.name(), isaac.name(), owen.name());
66+
Assertions.assertThat(things.tenants.list()).as("no tenants after deletion").isEmpty();
67+
Assertions.assertThat(things.tenants.exists(allison.name()))
68+
.describedAs("%s not exists", allison.name()).isFalse();
69+
Assertions.assertThat(things.tenants.exists(isaac.name()))
70+
.describedAs("%s not exists", isaac.name()).isFalse();
71+
Assertions.assertThat(things.tenants.exists(owen.name()))
72+
.describedAs("%s not exists", owen.name()).isFalse();
73+
}
74+
}

src/main/java/io/weaviate/client6/v1/api/collections/CollectionHandle.java

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,54 @@
77
import io.weaviate.client6.v1.api.collections.config.WeaviateConfigClient;
88
import io.weaviate.client6.v1.api.collections.data.WeaviateDataClient;
99
import io.weaviate.client6.v1.api.collections.pagination.Paginator;
10+
import io.weaviate.client6.v1.api.collections.query.ConsistencyLevel;
1011
import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClient;
12+
import io.weaviate.client6.v1.api.collections.tenants.WeaviateTenantsClient;
1113
import io.weaviate.client6.v1.internal.ObjectBuilder;
1214
import io.weaviate.client6.v1.internal.grpc.GrpcTransport;
1315
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
1416
import io.weaviate.client6.v1.internal.rest.RestTransport;
1517

16-
public class CollectionHandle<T> {
18+
public class CollectionHandle<PropertiesT> {
1719
public final WeaviateConfigClient config;
18-
public final WeaviateDataClient<T> data;
19-
public final WeaviateQueryClient<T> query;
20+
public final WeaviateDataClient<PropertiesT> data;
21+
public final WeaviateQueryClient<PropertiesT> query;
2022
public final WeaviateAggregateClient aggregate;
23+
public final WeaviateTenantsClient tenants;
24+
25+
private final CollectionHandleDefaults defaults;
2126

2227
public CollectionHandle(
2328
RestTransport restTransport,
2429
GrpcTransport grpcTransport,
25-
CollectionDescriptor<T> collectionDescriptor) {
30+
CollectionDescriptor<PropertiesT> collection,
31+
CollectionHandleDefaults defaults) {
32+
this.config = new WeaviateConfigClient(collection, restTransport, grpcTransport, defaults);
33+
this.aggregate = new WeaviateAggregateClient(collection, grpcTransport, defaults);
34+
this.query = new WeaviateQueryClient<>(collection, grpcTransport, defaults);
35+
this.data = new WeaviateDataClient<>(collection, restTransport, grpcTransport, defaults);
36+
this.defaults = defaults;
37+
38+
this.tenants = new WeaviateTenantsClient(collection, restTransport, grpcTransport);
39+
}
40+
41+
/** Copy constructor that sets new defaults. */
42+
private CollectionHandle(CollectionHandle<PropertiesT> c, CollectionHandleDefaults defaults) {
43+
this.config = new WeaviateConfigClient(c.config, defaults);
44+
this.aggregate = new WeaviateAggregateClient(c.aggregate, defaults);
45+
this.query = new WeaviateQueryClient<>(c.query, defaults);
46+
this.data = new WeaviateDataClient<>(c.data, defaults);
47+
this.defaults = defaults;
2648

27-
this.config = new WeaviateConfigClient(collectionDescriptor, restTransport, grpcTransport);
28-
this.data = new WeaviateDataClient<>(collectionDescriptor, restTransport, grpcTransport);
29-
this.query = new WeaviateQueryClient<>(collectionDescriptor, grpcTransport);
30-
this.aggregate = new WeaviateAggregateClient(collectionDescriptor, grpcTransport);
49+
this.tenants = c.tenants;
3150
}
3251

33-
public Paginator<T> paginate() {
52+
public Paginator<PropertiesT> paginate() {
3453
return Paginator.of(this.query);
3554
}
3655

37-
public Paginator<T> paginate(Function<Paginator.Builder<T>, ObjectBuilder<Paginator<T>>> fn) {
56+
public Paginator<PropertiesT> paginate(
57+
Function<Paginator.Builder<PropertiesT>, ObjectBuilder<Paginator<PropertiesT>>> fn) {
3858
return Paginator.of(this.query, fn);
3959
}
4060

@@ -57,4 +77,25 @@ public Paginator<T> paginate(Function<Paginator.Builder<T>, ObjectBuilder<Pagina
5777
public long size() {
5878
return this.aggregate.overAll(all -> all.includeTotalCount(true)).totalCount();
5979
}
80+
81+
public ConsistencyLevel consistencyLevel() {
82+
return defaults.consistencyLevel();
83+
}
84+
85+
public CollectionHandle<PropertiesT> withConsistencyLevel(ConsistencyLevel consistencyLevel) {
86+
return new CollectionHandle<>(this, CollectionHandleDefaults.of(with -> with.consistencyLevel(consistencyLevel)));
87+
}
88+
89+
public String tenant() {
90+
return defaults.tenant();
91+
}
92+
93+
public CollectionHandle<PropertiesT> withTenant(String tenant) {
94+
return new CollectionHandle<>(this, CollectionHandleDefaults.of(with -> with.tenant(tenant)));
95+
}
96+
97+
public CollectionHandle<PropertiesT> withDefaults(
98+
Function<CollectionHandleDefaults.Builder, ObjectBuilder<CollectionHandleDefaults>> fn) {
99+
return new CollectionHandle<>(this, CollectionHandleDefaults.of(fn));
100+
}
60101
}

src/main/java/io/weaviate/client6/v1/api/collections/CollectionHandleAsync.java

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import io.weaviate.client6.v1.api.collections.config.WeaviateConfigClientAsync;
1010
import io.weaviate.client6.v1.api.collections.data.WeaviateDataClientAsync;
1111
import io.weaviate.client6.v1.api.collections.pagination.AsyncPaginator;
12+
import io.weaviate.client6.v1.api.collections.query.ConsistencyLevel;
1213
import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClientAsync;
14+
import io.weaviate.client6.v1.api.collections.tenants.WeaviateTenantsClientAsync;
1315
import io.weaviate.client6.v1.internal.ObjectBuilder;
1416
import io.weaviate.client6.v1.internal.grpc.GrpcTransport;
1517
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
@@ -20,16 +22,34 @@ public class CollectionHandleAsync<PropertiesT> {
2022
public final WeaviateDataClientAsync<PropertiesT> data;
2123
public final WeaviateQueryClientAsync<PropertiesT> query;
2224
public final WeaviateAggregateClientAsync aggregate;
25+
public final WeaviateTenantsClientAsync tenants;
26+
27+
private final CollectionHandleDefaults defaults;
2328

2429
public CollectionHandleAsync(
2530
RestTransport restTransport,
2631
GrpcTransport grpcTransport,
27-
CollectionDescriptor<PropertiesT> collectionDescriptor) {
32+
CollectionDescriptor<PropertiesT> collection,
33+
CollectionHandleDefaults defaults) {
34+
35+
this.config = new WeaviateConfigClientAsync(collection, restTransport, grpcTransport, defaults);
36+
this.aggregate = new WeaviateAggregateClientAsync(collection, grpcTransport, defaults);
37+
this.query = new WeaviateQueryClientAsync<>(collection, grpcTransport, defaults);
38+
this.data = new WeaviateDataClientAsync<>(collection, restTransport, grpcTransport, defaults);
39+
this.defaults = defaults;
40+
41+
this.tenants = new WeaviateTenantsClientAsync(collection, restTransport, grpcTransport);
42+
}
2843

29-
this.config = new WeaviateConfigClientAsync(collectionDescriptor, restTransport, grpcTransport);
30-
this.data = new WeaviateDataClientAsync<>(collectionDescriptor, restTransport, grpcTransport);
31-
this.query = new WeaviateQueryClientAsync<>(collectionDescriptor, grpcTransport);
32-
this.aggregate = new WeaviateAggregateClientAsync(collectionDescriptor, grpcTransport);
44+
/** Copy constructor that sets new defaults. */
45+
private CollectionHandleAsync(CollectionHandleAsync<PropertiesT> c, CollectionHandleDefaults defaults) {
46+
this.config = new WeaviateConfigClientAsync(c.config, defaults);
47+
this.aggregate = new WeaviateAggregateClientAsync(c.aggregate, defaults);
48+
this.query = new WeaviateQueryClientAsync<>(c.query, defaults);
49+
this.data = new WeaviateDataClientAsync<>(c.data, defaults);
50+
this.defaults = defaults;
51+
52+
this.tenants = c.tenants;
3353
}
3454

3555
public AsyncPaginator<PropertiesT> paginate() {
@@ -64,4 +84,26 @@ public CompletableFuture<Long> size() {
6484
return this.aggregate.overAll(all -> all.includeTotalCount(true))
6585
.thenApply(AggregateResponse::totalCount);
6686
}
87+
88+
public ConsistencyLevel consistencyLevel() {
89+
return defaults.consistencyLevel();
90+
}
91+
92+
public CollectionHandleAsync<PropertiesT> withConsistencyLevel(ConsistencyLevel consistencyLevel) {
93+
return new CollectionHandleAsync<>(this, CollectionHandleDefaults.of(
94+
def -> def.consistencyLevel(consistencyLevel)));
95+
}
96+
97+
public String tenant() {
98+
return defaults.tenant();
99+
}
100+
101+
public CollectionHandleAsync<PropertiesT> withTenant(String tenant) {
102+
return new CollectionHandleAsync<>(this, CollectionHandleDefaults.of(with -> with.tenant(tenant)));
103+
}
104+
105+
public CollectionHandleAsync<PropertiesT> withDefaults(
106+
Function<CollectionHandleDefaults.Builder, ObjectBuilder<CollectionHandleDefaults>> fn) {
107+
return new CollectionHandleAsync<>(this, CollectionHandleDefaults.of(fn));
108+
}
67109
}

0 commit comments

Comments
 (0)