Skip to content

Commit d87cc9a

Browse files
Merge pull request #602 from SpineEventEngine/aggregate-storage-events-compacting
Remove an enrichment information from events before storing to `AggregateStorage`
2 parents d202837 + 5fb23f8 commit d87cc9a

File tree

9 files changed

+246
-101
lines changed

9 files changed

+246
-101
lines changed

core/src/main/java/io/spine/core/Events.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
import static com.google.common.base.Preconditions.checkNotNull;
3838
import static io.spine.protobuf.AnyPacker.unpack;
39+
import static io.spine.util.Exceptions.newIllegalStateException;
3940
import static io.spine.validate.Validate.checkNotEmptyOrBlank;
4041

4142
/**
@@ -217,6 +218,56 @@ public static boolean isExternal(EventContext context) {
217218
return context.getExternal();
218219
}
219220

221+
/**
222+
* Clears enrichments of the specified event.
223+
*
224+
* <p>Use this method to decrease a size of an event, if enrichments aren't important.
225+
*
226+
* <p>A result won't contain:
227+
* <ul>
228+
* <li>the enrichment from the event context;</li>
229+
* <li>the enrichment from the first-level origin.</li>
230+
* </ul>
231+
*
232+
* <p>Enrichments will not be removed from second-level and deeper origins,
233+
* because it's a heavy performance operation.
234+
*
235+
* @param event the event to clear enrichments
236+
* @return the event without enrichments
237+
*/
238+
@Internal
239+
public static Event clearEnrichments(Event event) {
240+
final EventContext context = event.getContext();
241+
final EventContext.Builder resultContext = context.toBuilder()
242+
.clearEnrichment();
243+
final EventContext.OriginCase originCase = resultContext.getOriginCase();
244+
switch (originCase) {
245+
case EVENT_CONTEXT:
246+
resultContext.setEventContext(context.getEventContext()
247+
.toBuilder()
248+
.clearEnrichment());
249+
break;
250+
case REJECTION_CONTEXT:
251+
resultContext.setRejectionContext(context.getRejectionContext()
252+
.toBuilder()
253+
.clearEnrichment());
254+
break;
255+
case COMMAND_CONTEXT:
256+
// Nothing to remove.
257+
break;
258+
case ORIGIN_NOT_SET:
259+
// Does nothing because there is no origin for this event.
260+
break;
261+
default:
262+
throw newIllegalStateException("Unsupported origin case is encountered: %s",
263+
originCase);
264+
}
265+
final Event result = event.toBuilder()
266+
.setContext(resultContext)
267+
.build();
268+
return result;
269+
}
270+
220271
/**
221272
* The stringifier of event IDs.
222273
*/

core/src/main/proto/spine/core/enrichment.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import "google/protobuf/any.proto";
3434
// Attributes with additional information (enrichment) for an outer message.
3535
//
3636
// A message can be enriched with one or more messages. For example, an `Event` can be enriched with
37-
// information for easier building of user interface projections. A `Rejection` can be eriched with
37+
// information for easier building of user interface projections. A `Rejection` can be enriched with
3838
// additional information on why the command was rejected.
3939
//
4040
// If message enrichment should not be performed (e.g. because of performance or security

ext.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* as we want to manage the versions in a single source.
2626
*/
2727

28-
def final SPINE_VERSION = '0.9.77-SNAPSHOT'
28+
def final SPINE_VERSION = '0.9.78-SNAPSHOT'
2929

3030
ext {
3131
// The version of the modules in this project.

server/src/main/java/io/spine/server/aggregate/AggregateStorage.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import static com.google.common.collect.Lists.newLinkedList;
3939
import static com.google.protobuf.TextFormat.shortDebugString;
4040
import static com.google.protobuf.util.Timestamps.checkValid;
41+
import static io.spine.core.Events.clearEnrichments;
4142
import static io.spine.util.Exceptions.newIllegalStateException;
4243
import static io.spine.validate.Validate.checkNotEmptyOrBlank;
4344

@@ -156,13 +157,17 @@ public void write(I id, AggregateStateRecord events) {
156157
/**
157158
* Writes an event to the storage by an aggregate ID.
158159
*
160+
* <p>Before the storing, {@linkplain io.spine.core.Events#clearEnrichments(Event) enrichments}
161+
* will be removed from the event.
162+
*
159163
* @param id the aggregate ID
160164
* @param event the event to write
161165
*/
162166
void writeEvent(I id, Event event) {
163167
checkNotClosedAndArguments(id, event);
164168

165-
final AggregateEventRecord record = toStorageRecord(event);
169+
final Event eventWithoutEnrichments = clearEnrichments(event);
170+
final AggregateEventRecord record = toStorageRecord(eventWithoutEnrichments);
166171
writeRecord(id, record);
167172
}
168173

server/src/main/java/io/spine/server/event/EEntity.java

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.google.protobuf.Timestamp;
2424
import io.spine.annotation.Internal;
2525
import io.spine.core.Event;
26-
import io.spine.core.EventContext;
2726
import io.spine.core.EventEnvelope;
2827
import io.spine.core.EventId;
2928
import io.spine.core.Events;
@@ -34,10 +33,12 @@
3433
import javax.annotation.Nullable;
3534
import java.util.Comparator;
3635

37-
import static io.spine.util.Exceptions.newIllegalStateException;
36+
import static io.spine.core.Events.clearEnrichments;
3837

3938
/**
40-
* Stores an event.
39+
* An entity for storing an event.
40+
*
41+
* <p>An underlying event doesn't contain {@linkplain Events#clearEnrichments(Event) enrichments}.
4142
*
4243
* @author Alexander Yevsyukov
4344
* @author Dmytro Dashenkov
@@ -87,8 +88,8 @@ public int compare(EEntity e1, EEntity e2) {
8788

8889
EEntity(Event event) {
8990
this(event.getId());
90-
final Event compactedEvent = compact(event);
91-
updateState(compactedEvent);
91+
final Event eventWithoutEnrichments = clearEnrichments(event);
92+
updateState(eventWithoutEnrichments);
9293
}
9394

9495
/**
@@ -128,49 +129,4 @@ public String getType() {
128129
}
129130
return typeName.value();
130131
}
131-
132-
/**
133-
* Obtains the compacted version of the event.
134-
*
135-
* <p>A compacted version doesn't contain:
136-
* <ul>
137-
* <li>the enrichment from the event context</li>
138-
* <li>the enrichment from the origin</li>
139-
* <li>nested origins if the origin is {@link EventContext}</li>
140-
* </ul>
141-
*
142-
* @param event the event to compact
143-
* @return the compacted event
144-
*/
145-
private static Event compact(Event event) {
146-
final EventContext context = event.getContext();
147-
final EventContext.Builder resultContext = context.toBuilder()
148-
.clearEnrichment();
149-
final EventContext.OriginCase originCase = resultContext.getOriginCase();
150-
switch (originCase) {
151-
case EVENT_CONTEXT:
152-
resultContext.setEventContext(context.getEventContext()
153-
.toBuilder()
154-
.clearOrigin()
155-
.clearEnrichment());
156-
break;
157-
case REJECTION_CONTEXT:
158-
resultContext.setRejectionContext(context.getRejectionContext()
159-
.toBuilder()
160-
.clearEnrichment());
161-
break;
162-
case COMMAND_CONTEXT:
163-
// Does nothing.
164-
break;
165-
case ORIGIN_NOT_SET:
166-
// Does nothing because there is no origin for this event.
167-
break;
168-
default:
169-
throw newIllegalStateException("Unsupported origin case encountered: %s",
170-
originCase);
171-
}
172-
return event.toBuilder()
173-
.setContext(resultContext)
174-
.build();
175-
}
176132
}

server/src/test/java/io/spine/server/aggregate/AggregateStorageShould.java

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import com.google.protobuf.Timestamp;
2828
import com.google.protobuf.util.Timestamps;
2929
import io.spine.core.Event;
30+
import io.spine.core.EventContext;
31+
import io.spine.core.RejectionContext;
3032
import io.spine.core.Version;
3133
import io.spine.server.aggregate.given.Given.StorageRecord;
3234
import io.spine.server.command.TestEventFactory;
@@ -52,10 +54,12 @@
5254
import static io.spine.Identifier.newUuid;
5355
import static io.spine.core.Versions.increment;
5456
import static io.spine.core.Versions.zero;
57+
import static io.spine.core.given.GivenEnrichment.withOneAttribute;
5558
import static io.spine.server.aggregate.given.Given.StorageRecords.sequenceFor;
5659
import static io.spine.server.command.TestEventFactory.newInstance;
5760
import static io.spine.time.Durations2.seconds;
5861
import static io.spine.time.Time.getCurrentTime;
62+
import static io.spine.validate.Validate.isDefault;
5963
import static java.lang.Integer.MAX_VALUE;
6064
import static java.util.Collections.reverse;
6165
import static org.junit.Assert.assertEquals;
@@ -345,6 +349,65 @@ public void continue_history_reading_if_snapshot_was_not_found_in_first_batch()
345349
assertEquals(eventCountAfterSnapshot, stateRecord.getEventCount());
346350
}
347351

352+
@Test
353+
public void not_store_enrichment_for_EventContext() {
354+
final EventContext enrichedContext = EventContext.newBuilder()
355+
.setEnrichment(withOneAttribute())
356+
.build();
357+
final Event event = Event.newBuilder()
358+
.setContext(enrichedContext)
359+
.setMessage(Any.getDefaultInstance())
360+
.build();
361+
storage.writeEvent(id, event);
362+
final EventContext loadedContext = storage.read(newReadRequest(id))
363+
.get()
364+
.getEvent(0)
365+
.getContext();
366+
assertTrue(isDefault(loadedContext.getEnrichment()));
367+
}
368+
369+
@Test
370+
public void not_store_enrichment_for_origin_of_RejectionContext_type() {
371+
final RejectionContext origin = RejectionContext.newBuilder()
372+
.setEnrichment(withOneAttribute())
373+
.build();
374+
final EventContext context = EventContext.newBuilder()
375+
.setRejectionContext(origin)
376+
.build();
377+
final Event event = Event.newBuilder()
378+
.setContext(context)
379+
.setMessage(Any.getDefaultInstance())
380+
.build();
381+
storage.writeEvent(id, event);
382+
final RejectionContext loadedOrigin = storage.read(newReadRequest(id))
383+
.get()
384+
.getEvent(0)
385+
.getContext()
386+
.getRejectionContext();
387+
assertTrue(isDefault(loadedOrigin.getEnrichment()));
388+
}
389+
390+
@Test
391+
public void not_store_enrichment_for_origin_of_EventContext_type() {
392+
final EventContext origin = EventContext.newBuilder()
393+
.setEnrichment(withOneAttribute())
394+
.build();
395+
final EventContext context = EventContext.newBuilder()
396+
.setEventContext(origin)
397+
.build();
398+
final Event event = Event.newBuilder()
399+
.setContext(context)
400+
.setMessage(Any.getDefaultInstance())
401+
.build();
402+
storage.writeEvent(id, event);
403+
final EventContext loadedOrigin = storage.read(newReadRequest(id))
404+
.get()
405+
.getEvent(0)
406+
.getContext()
407+
.getEventContext();
408+
assertTrue(isDefault(loadedOrigin.getEnrichment()));
409+
}
410+
348411
@Test(expected = IllegalStateException.class)
349412
public void throw_exception_if_try_to_write_event_count_to_closed_storage() {
350413
close(storage);
@@ -402,18 +465,18 @@ protected void writeAll(ProjectId id, Iterable<AggregateEventRecord> records) {
402465
}
403466

404467
private Iterator<AggregateEventRecord> historyBackward() {
405-
final AggregateReadRequest<ProjectId> readRequest = new AggregateReadRequest<>(id, MAX_VALUE);
468+
final AggregateReadRequest<ProjectId> readRequest = newReadRequest(id);
406469
return storage.historyBackward(readRequest);
407470
}
408471

409472
protected static final Function<AggregateEventRecord, Event> TO_EVENT =
410473
new Function<AggregateEventRecord, Event>() {
411-
@Nullable // return null because an exception won't be propagated in this case
412-
@Override
413-
public Event apply(@Nullable AggregateEventRecord input) {
414-
return (input == null) ? null : input.getEvent();
415-
}
416-
};
474+
@Nullable // return null because an exception won't be propagated in this case
475+
@Override
476+
public Event apply(@Nullable AggregateEventRecord input) {
477+
return (input == null) ? null : input.getEvent();
478+
}
479+
};
417480

418481
private static Snapshot newSnapshot(Timestamp time) {
419482
return Snapshot.newBuilder()

0 commit comments

Comments
 (0)