Skip to content

Commit

Permalink
Merge pull request #1533 from SpineEventEngine/expose-storage-column-…
Browse files Browse the repository at this point in the history
…defs

Make Storage API and implementation more friendly to Spine's storage-specific libraries
  • Loading branch information
armiol authored Nov 9, 2023
2 parents 349fc83 + e4ca6ea commit e00ad8f
Show file tree
Hide file tree
Showing 71 changed files with 1,653 additions and 2,202 deletions.
24 changes: 12 additions & 12 deletions license-report.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


# Dependencies of `io.spine:spine-client:2.0.0-SNAPSHOT.173`
# Dependencies of `io.spine:spine-client:2.0.0-SNAPSHOT.174`

## Runtime
1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4.
Expand Down Expand Up @@ -817,12 +817,12 @@

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Sat Nov 04 20:26:12 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Wed Nov 08 14:13:56 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine:spine-core:2.0.0-SNAPSHOT.173`
# Dependencies of `io.spine:spine-core:2.0.0-SNAPSHOT.174`

## Runtime
1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2.
Expand Down Expand Up @@ -1591,12 +1591,12 @@ This report was generated on **Sat Nov 04 20:26:12 WET 2023** using [Gradle-Lice

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Sat Nov 04 20:26:13 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Wed Nov 08 14:13:56 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine:spine-server:2.0.0-SNAPSHOT.173`
# Dependencies of `io.spine:spine-server:2.0.0-SNAPSHOT.174`

## Runtime
1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4.
Expand Down Expand Up @@ -2421,12 +2421,12 @@ This report was generated on **Sat Nov 04 20:26:13 WET 2023** using [Gradle-Lice

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Sat Nov 04 20:26:13 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Wed Nov 08 14:13:57 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.tools:spine-testutil-client:2.0.0-SNAPSHOT.173`
# Dependencies of `io.spine.tools:spine-testutil-client:2.0.0-SNAPSHOT.174`

## Runtime
1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4.
Expand Down Expand Up @@ -3358,12 +3358,12 @@ This report was generated on **Sat Nov 04 20:26:13 WET 2023** using [Gradle-Lice

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Sat Nov 04 20:26:14 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Wed Nov 08 14:13:57 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.tools:spine-testutil-core:2.0.0-SNAPSHOT.173`
# Dependencies of `io.spine.tools:spine-testutil-core:2.0.0-SNAPSHOT.174`

## Runtime
1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4.
Expand Down Expand Up @@ -4295,12 +4295,12 @@ This report was generated on **Sat Nov 04 20:26:14 WET 2023** using [Gradle-Lice

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Sat Nov 04 20:26:14 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Wed Nov 08 14:13:57 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.tools:spine-testutil-server:2.0.0-SNAPSHOT.173`
# Dependencies of `io.spine.tools:spine-testutil-server:2.0.0-SNAPSHOT.174`

## Runtime
1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4.
Expand Down Expand Up @@ -5280,4 +5280,4 @@ This report was generated on **Sat Nov 04 20:26:14 WET 2023** using [Gradle-Lice

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Sat Nov 04 20:26:15 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Wed Nov 08 14:13:58 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject.
-->
<groupId>io.spine</groupId>
<artifactId>spine-core-java</artifactId>
<version>2.0.0-SNAPSHOT.173</version>
<version>2.0.0-SNAPSHOT.174</version>

<inceptionYear>2015</inceptionYear>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,40 @@
* Columns stored along with an {@link AggregateEventRecord}.
*/
@RecordColumns(ofType = AggregateEventRecord.class)
@SuppressWarnings(
{"DuplicateStringLiteralInspection", /* Column names may repeat across records. */
"BadImport"}) /* `create` looks fine in this context. */
final class AggregateEventRecordColumn {
@SuppressWarnings({
"DuplicateStringLiteralInspection" /* Column names may repeat across records. */,
"BadImport" /* `create` looks fine in this context. */,
"WeakerAccess" /* This type is used in downstream Spine libraries. */})
public final class AggregateEventRecordColumn {

/**
* Stores the identifier of an aggregate.
*/
static final RecordColumn<AggregateEventRecord, Any>
public static final RecordColumn<AggregateEventRecord, Any>
aggregate_id = create("aggregate_id", Any.class, AggregateEventRecord::getAggregateId);

/**
* Stores the time when the event record was created.
*/
static final RecordColumn<AggregateEventRecord, Timestamp>
public static final RecordColumn<AggregateEventRecord, Timestamp>
created = create("created", Timestamp.class, AggregateEventRecord::getTimestamp);

/**
* Stores the version of the record, either of the stored event, or the snapshot.
*/
static final RecordColumn<AggregateEventRecord, Integer>
public static final RecordColumn<AggregateEventRecord, Integer>
version = create("version", Integer.class, new GetVersion());

/**
* Stores {@code true} for the records which hold snapshots, {@code false} otherwise.
*/
static final RecordColumn<AggregateEventRecord, Boolean>
public static final RecordColumn<AggregateEventRecord, Boolean>
snapshot = create("snapshot", Boolean.class, AggregateEventRecord::hasSnapshot);

/**
* Prevents this type from instantiation.
*
* <p>This class exists exclusively as a container of the column definitions. Thus it isn't
* <p>This class exists exclusively as a container of the column definitions. Thus, it isn't
* expected to be instantiated at all. See the {@link RecordColumns} docs for more details on
* this approach.
*/
Expand All @@ -82,7 +83,7 @@ private AggregateEventRecordColumn() {
/**
* Returns all the column definitions.
*/
static Columns<AggregateEventRecord> definitions() {
public static Columns<AggregateEventRecord> definitions() {
return Columns.of(aggregate_id, created, version, snapshot);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import io.spine.query.RecordQuery;
import io.spine.server.ContextSpec;
import io.spine.server.storage.MessageRecordSpec;
import io.spine.server.storage.RecordSpec;
import io.spine.server.storage.MessageStorage;
import io.spine.server.storage.StorageFactory;

Expand All @@ -46,8 +46,8 @@ public class AggregateEventStorage
* A specification on how to store the event records of an aggregate.
*/
@SuppressWarnings("ConstantConditions") // Protobuf getters return non-{@code null} values.
private static final MessageRecordSpec<AggregateEventRecordId, AggregateEventRecord> spec =
new MessageRecordSpec<>(
private static final RecordSpec<AggregateEventRecordId, AggregateEventRecord> spec =
new RecordSpec<>(
AggregateEventRecordId.class,
AggregateEventRecord.class,
AggregateEventRecord::getId,
Expand Down Expand Up @@ -99,4 +99,14 @@ protected boolean delete(AggregateEventRecordId id) {
protected void deleteAll(Iterable<AggregateEventRecordId> ids) {
super.deleteAll(ids);
}

/**
* {@inheritDoc}
*
* <p>This method is exposed to {@code public} for SPI users.
*/
@Override
public void write(AggregateEventRecord record) {
super.write(record);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@
import io.spine.server.ContextSpec;
import io.spine.server.entity.EntityRecord;
import io.spine.server.entity.storage.EntityRecordStorage;
import io.spine.server.entity.storage.EntityRecordWithColumns;
import io.spine.server.entity.storage.ToEntityRecordQuery;
import io.spine.server.storage.AbstractStorage;
import io.spine.server.storage.QueryConverter;
import io.spine.server.storage.RecordWithColumns;
import io.spine.server.storage.StorageFactory;
import org.checkerframework.checker.nullness.qual.Nullable;

Expand Down Expand Up @@ -72,7 +72,7 @@
* <h3>Storing Aggregate events</h3>
*
* <p>Each Aggregate is an event-sourced Entity. To load an Aggregate instance, one plays all
* of the events emitted by it, eventually obtaining the last known state. While the Event Store
* the events emitted by it, eventually obtaining the last known state. While the Event Store
* of a Bounded Context, to which some Aggregate belongs, stores all domain events, using it
* for the sake of loading an Aggregate is inefficient in most cases. An overwhelming number of
* the domain events emitted in a Bounded Context and the restrictions applied by an underlying
Expand Down Expand Up @@ -300,7 +300,7 @@ var record = newEventRecord(aggregateId, snapshot);
* the record to write
*/
protected void writeEventRecord(I id, AggregateEventRecord record) {
eventStorage.write(record.getId(), record);
eventStorage.write(record);
}

/**
Expand Down Expand Up @@ -368,14 +368,12 @@ private void ensureStatesQueryable() {
}

private Class<? extends EntityState<?>> stateClass() {
return stateStorage.recordSpec()
.entityClass()
.stateClass();
return stateStorage.stateClass();
}

protected void writeState(Aggregate<I, ?, ?> aggregate) {
var record = AggregateRecords.newStateRecord(aggregate, queryingEnabled);
var result = EntityRecordWithColumns.create(aggregate, record);
var result = RecordWithColumns.create(record, stateStorage.recordSpec());
stateStorage.write(result);
}

Expand Down Expand Up @@ -417,7 +415,9 @@ Iterator<AggregateEventRecord> historyBackward(I id, int batchSize) {
*/
protected Iterator<AggregateEventRecord>
historyBackward(I id, int batchSize, @Nullable Version startingFrom) {
return historyBackward.read(id, batchSize, startingFrom);
var original = historyBackward.read(id, batchSize, startingFrom);
var copied = ImmutableList.copyOf(original);
return copied.iterator();
}

/**
Expand Down
25 changes: 19 additions & 6 deletions server/src/main/java/io/spine/server/delivery/CatchUpStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import io.spine.annotation.SPI;
import io.spine.server.storage.MessageRecordSpec;
import io.spine.server.storage.RecordSpec;
import io.spine.server.storage.MessageStorage;
import io.spine.server.storage.StorageFactory;
import io.spine.type.TypeUrl;
Expand All @@ -44,17 +44,30 @@
@SPI
public class CatchUpStorage extends MessageStorage<CatchUpId, CatchUp> {

/**
* Creates a new instance of this storage.
*
* <p>It is recommended to have {@code CatchUpStorage} instances single-tenant only.
* It is so, because no distinction should be made for processing of {@code InboxMessage}s
* sent during the catch-up process, since it is batch-based anyway,
* and splitting batches even more (across tenants) reduces the performance.
*
* @param factory
* storage factory to create an underlying record storage
* @param multitenant
* whether {@code CatchUpStorage} should be multi-tenant
*/
public CatchUpStorage(StorageFactory factory, boolean multitenant) {
super(Delivery.contextSpec(multitenant),
factory.createRecordStorage(Delivery.contextSpec(multitenant), getSpec()));
}

@SuppressWarnings("ConstantConditions") // Protobuf getters do not return {@code null}.
private static MessageRecordSpec<CatchUpId, CatchUp> getSpec() {
return new MessageRecordSpec<>(CatchUpId.class,
CatchUp.class,
CatchUp::getId,
CatchUpColumn.definitions());
private static RecordSpec<CatchUpId, CatchUp> getSpec() {
return new RecordSpec<>(CatchUpId.class,
CatchUp.class,
CatchUp::getId,
CatchUpColumn.definitions());
}

/**
Expand Down
13 changes: 10 additions & 3 deletions server/src/main/java/io/spine/server/delivery/Delivery.java
Original file line number Diff line number Diff line change
Expand Up @@ -792,10 +792,17 @@ protected void onShardUpdated(InboxMessage message) {

/**
* Returns the specification of a Bounded Context describing the {@code Delivery} flow.
* @param multitenant whether the Bounded Context supports multi-tenancy
*
* <p>Usually, this context is single-tenant, as the batch processing
* of {@code InboxMessage}s is more effective when the batches are not
* split across tenants.
*
* @param multitenant
* whether the Bounded Context supports multi-tenancy
*/
@SuppressWarnings("TestOnlyProblems") // The called code is not test-only.
static ContextSpec contextSpec(boolean multitenant) {
@SuppressWarnings({"TestOnlyProblems" /* The called code is not test-only. */,
"WeakerAccess" /* Used in descendant libraries to configure storage. */})
public static ContextSpec contextSpec(boolean multitenant) {
var name = SYSTEM_DELIVERY.value();
return multitenant ?
ContextSpec.multitenant(name) :
Expand Down
25 changes: 19 additions & 6 deletions server/src/main/java/io/spine/server/delivery/InboxStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import com.google.protobuf.Timestamp;
import io.spine.annotation.SPI;
import io.spine.query.RecordQueryBuilder;
import io.spine.server.storage.MessageRecordSpec;
import io.spine.server.storage.RecordSpec;
import io.spine.server.storage.MessageStorage;
import io.spine.server.storage.StorageFactory;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand Down Expand Up @@ -58,17 +58,30 @@
@SPI
public class InboxStorage extends MessageStorage<InboxMessageId, InboxMessage> {

/**
* Creates a new instance of this storage.
*
* <p>Generally, {@code InboxStorage} instances should be single-tenant only.
* It is so, because no distinction should be made for processing of {@code InboxMessage}s,
* since it is batch-based anyway, and splitting batches even more (across tenants)
* reduces the performance.
*
* @param factory
* storage factory to create an underlying record storage
* @param multitenant
* whether {@code InboxStorage} should be multi-tenant
*/
public InboxStorage(StorageFactory factory, boolean multitenant) {
super(Delivery.contextSpec(multitenant),
factory.createRecordStorage(Delivery.contextSpec(multitenant), spec()));
}

private static MessageRecordSpec<InboxMessageId, InboxMessage> spec() {
private static RecordSpec<InboxMessageId, InboxMessage> spec() {
@SuppressWarnings("ConstantConditions") // Protobuf getters do not return {@code null}s.
var spec = new MessageRecordSpec<>(InboxMessageId.class,
InboxMessage.class,
InboxMessage::getId,
InboxColumn.definitions());
var spec = new RecordSpec<>(InboxMessageId.class,
InboxMessage.class,
InboxMessage::getId,
InboxColumn.definitions());
return spec;
}

Expand Down
21 changes: 7 additions & 14 deletions server/src/main/java/io/spine/server/entity/DefaultConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@
/**
* Default implementation of {@code EntityStorageConverter} for {@code AbstractEntity}.
*
* @param <I> the type of entity IDs
* @param <E> the type of entities
* @param <S> the type of entity states
* @param <I>
* the type of entity IDs
* @param <E>
* the type of entities
* @param <S>
* the type of entity states
*/
final class DefaultConverter<I, E extends AbstractEntity<I, S>, S extends EntityState<I>>
extends StorageConverter<I, E, S> {
Expand All @@ -59,19 +62,9 @@ public StorageConverter<I, E, S> withFieldMask(FieldMask fieldMask) {
return new DefaultConverter<>(stateType, factory, fieldMask);
}

/**
* Sets lifecycle flags in the builder from the entity.
*
* @param builder
* the entity builder to update
* @param entity
* the entity which data is passed to the {@link EntityRecord} we are building
*/
@SuppressWarnings("CheckReturnValue") // calling builder
@Override
protected void updateBuilder(EntityRecord.Builder builder, E entity) {
builder.setVersion(entity.version())
.setLifecycleFlags(entity.lifecycleFlags());
// Do nothing here.
}

/**
Expand Down
Loading

0 comments on commit e00ad8f

Please sign in to comment.