Skip to content

Commit 7e72b91

Browse files
committed
[Fix #1691] Moving from int index to string generated index
Signed-off-by: Francisco Javier Tirado Sarti <ftirados@ibm.com>
1 parent f3bc27d commit 7e72b91

7 files changed

Lines changed: 49 additions & 89 deletions

File tree

‎impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/PersistenceUtils.java‎

Lines changed: 0 additions & 40 deletions
This file was deleted.

‎impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/hashing/HashMappingCoordinator.java‎

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
*/
1616
package io.serverlessworkflow.impl.persistence.hashing;
1717

18+
import com.github.f4b6a3.ulid.UlidFactory;
1819
import java.util.ArrayList;
1920
import java.util.Arrays;
2021
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.Map;
24+
import java.util.Map.Entry;
2325
import java.util.Optional;
2426
import java.util.concurrent.ConcurrentHashMap;
2527
import java.util.function.Consumer;
@@ -28,8 +30,10 @@
2830

2931
public class HashMappingCoordinator {
3032

33+
private static final UlidFactory idFactory = UlidFactory.newMonotonicInstance();
34+
3135
public static final HashMappingCoordinator build(
32-
Function<String, Map<String, List<byte[]>>> retriever,
36+
Function<String, Map<String, Map<String, byte[]>>> retriever,
3337
Consumer<Map<String, List<HashMappingInfo>>> writer) {
3438
return new HashMappingCoordinator(retriever, writer);
3539
}
@@ -57,19 +61,19 @@ public boolean isTransient() {
5761
}
5862
}
5963

60-
private record PendingWrite(String key, int index, BytesWithFlag bytes) {}
64+
private record PendingWrite(String key, String index, BytesWithFlag bytes) {}
6165

62-
private final Function<String, Map<String, List<byte[]>>> retriever;
66+
private final Function<String, Map<String, Map<String, byte[]>>> retriever;
6367
private final Consumer<Map<String, List<HashMappingInfo>>> writer;
6468

6569
private HashMappingCoordinator(
66-
Function<String, Map<String, List<byte[]>>> retriever,
70+
Function<String, Map<String, Map<String, byte[]>>> retriever,
6771
Consumer<Map<String, List<HashMappingInfo>>> writer) {
6872
this.retriever = retriever;
6973
this.writer = writer;
7074
}
7175

72-
private static Map<String, Map<String, List<BytesWithFlag>>> mappingInfo =
76+
private static Map<String, Map<String, Map<String, BytesWithFlag>>> mappingInfo =
7377
new ConcurrentHashMap<>();
7478

7579
private Map<String, List<PendingWrite>> pending = new HashMap<>();
@@ -78,52 +82,45 @@ private HashMappingInfo from(PendingWrite pending) {
7882
return new HashMappingInfo(pending.key, pending.index, pending.bytes.bytes);
7983
}
8084

81-
public int calculateIndex(String instanceId, HashItem item, byte[] bytes) {
82-
Map<String, List<BytesWithFlag>> instanceMap = getInstanceMap(instanceId);
85+
public String calculateIndex(String instanceId, HashItem item, byte[] bytes) {
86+
Map<String, Map<String, BytesWithFlag>> instanceMap = getInstanceMap(instanceId);
8387
String key = item.key();
8488
synchronized (instanceMap) {
85-
List<BytesWithFlag> list = instanceMap.computeIfAbsent(key, __ -> new ArrayList<>());
86-
if (list.isEmpty()) {
87-
int index = 0;
88-
BytesWithFlag bytesWithFlag = new BytesWithFlag(bytes);
89-
list.add(bytesWithFlag);
90-
addWrite(instanceId, key, index, bytesWithFlag);
91-
return index;
92-
}
93-
for (int i = 0; i < list.size(); i++) {
94-
BytesWithFlag bytesWithFlag = list.get(i);
95-
if (Arrays.equals(bytesWithFlag.bytes, bytes)) {
96-
if (bytesWithFlag.isTransient()) {
97-
addWrite(instanceId, key, i, bytesWithFlag);
89+
Map<String, BytesWithFlag> duplicateMap =
90+
instanceMap.computeIfAbsent(key, __ -> new HashMap<>());
91+
92+
for (Entry<String, BytesWithFlag> entry : duplicateMap.entrySet()) {
93+
if (Arrays.equals(entry.getValue().bytes, bytes)) {
94+
if (entry.getValue().isTransient()) {
95+
addWrite(instanceId, key, entry.getKey(), entry.getValue());
9896
}
99-
return i;
97+
return entry.getKey();
10098
}
10199
}
100+
String index = idFactory.create().toString();
102101
BytesWithFlag bytesWithFlag = new BytesWithFlag(bytes);
103-
list.add(bytesWithFlag);
104-
int index = list.size() - 1;
102+
duplicateMap.put(index, bytesWithFlag);
105103
addWrite(instanceId, key, index, bytesWithFlag);
106104
return index;
107105
}
108106
}
109107

110-
private void addWrite(String instanceId, String key, int index, BytesWithFlag bytes) {
108+
private void addWrite(String instanceId, String key, String index, BytesWithFlag bytes) {
111109
pending
112110
.computeIfAbsent(instanceId, __ -> new ArrayList<>())
113111
.add(new PendingWrite(key, index, bytes));
114112
}
115113

116-
public Optional<byte[]> readBytes(String instanceId, HashItem item, int index) {
117-
Map<String, List<BytesWithFlag>> instanceMap = getInstanceMap(instanceId);
114+
public Optional<byte[]> readBytes(String instanceId, HashItem item, String index) {
115+
Map<String, Map<String, BytesWithFlag>> instanceMap = getInstanceMap(instanceId);
118116
synchronized (instanceMap) {
119117
return Optional.ofNullable(instanceMap.get(item.key()))
120-
.filter(list -> list.size() > index)
121-
.map(list -> list.get(index))
118+
.map(m -> m.get(index))
122119
.map(bytes -> bytes.bytes);
123120
}
124121
}
125122

126-
private Map<String, List<BytesWithFlag>> getInstanceMap(String instanceId) {
123+
private Map<String, Map<String, BytesWithFlag>> getInstanceMap(String instanceId) {
127124
return mappingInfo.computeIfAbsent(
128125
instanceId,
129126
k ->
@@ -132,9 +129,11 @@ private Map<String, List<BytesWithFlag>> getInstanceMap(String instanceId) {
132129
Collectors.toMap(
133130
Map.Entry::getKey,
134131
e ->
135-
e.getValue().stream()
136-
.map(b -> new BytesWithFlag(b, true))
137-
.collect(Collectors.toCollection(ArrayList::new)))));
132+
e.getValue().entrySet().stream()
133+
.collect(
134+
Collectors.toMap(
135+
Entry::getKey,
136+
v -> new BytesWithFlag(v.getValue(), true))))));
138137
}
139138

140139
public void persist() {
@@ -143,7 +142,7 @@ public void persist() {
143142
String instanceId = item.getKey();
144143
List<HashMappingInfo> list = new ArrayList<>();
145144
result.put(instanceId, list);
146-
Map<String, List<BytesWithFlag>> instanceMap = mappingInfo.get(instanceId);
145+
Map<String, Map<String, BytesWithFlag>> instanceMap = mappingInfo.get(instanceId);
147146
if (instanceMap != null) {
148147
synchronized (instanceMap) {
149148
item.getValue()
@@ -162,7 +161,7 @@ public void persist() {
162161
public void afterCommit() {
163162
for (Map.Entry<String, List<PendingWrite>> item : pending.entrySet()) {
164163
String instanceId = item.getKey();
165-
Map<String, List<BytesWithFlag>> instanceMap = mappingInfo.get(instanceId);
164+
Map<String, Map<String, BytesWithFlag>> instanceMap = mappingInfo.get(instanceId);
166165
if (instanceMap != null) {
167166
synchronized (instanceMap) {
168167
item.getValue().forEach(v -> v.bytes.persist());
@@ -176,7 +175,7 @@ public void afterRollback() {
176175
pending.clear();
177176
}
178177

179-
public void afterRemove(String instanceId) {
178+
public static void afterRemove(String instanceId) {
180179
mappingInfo.remove(instanceId);
181180
}
182181
}

‎impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/hashing/HashMappingInfo.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
*/
1616
package io.serverlessworkflow.impl.persistence.hashing;
1717

18-
public record HashMappingInfo(String key, int index, byte[] bytes) {}
18+
public record HashMappingInfo(String key, String index, byte[] bytes) {}

‎impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/hashing/IntegerHashItem.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
public class IntegerHashItem implements HashItem {
2323

2424
public static final byte ID = 1;
25-
public static final int SIZE_THRESHOLD = 4 * 4;
25+
public static final int SIZE_THRESHOLD = 32;
2626

2727
private final int hashCode;
2828

‎impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/hashing/MD5HashItem.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
public class MD5HashItem implements HashItem {
2424

2525
public static final byte ID = 2;
26-
public static final int SIZE_THRESHOLD = 128 * 2;
26+
public static final int SIZE_THRESHOLD = 150;
2727

2828
@Override
2929
public byte id() {

‎impl/persistence/bigmap/src/main/java/io/serverlessworkflow/impl/persistence/bigmap/BytesMapInstanceTransaction.java‎

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import io.serverlessworkflow.impl.persistence.CompletedTaskInfo;
3434
import io.serverlessworkflow.impl.persistence.PersistenceInstanceInfo;
3535
import io.serverlessworkflow.impl.persistence.PersistenceTaskInfo;
36-
import io.serverlessworkflow.impl.persistence.PersistenceUtils;
3736
import io.serverlessworkflow.impl.persistence.RetriedTaskInfo;
3837
import io.serverlessworkflow.impl.persistence.hashing.HashFactory;
3938
import io.serverlessworkflow.impl.persistence.hashing.HashItem;
@@ -70,15 +69,13 @@ protected BytesMapInstanceTransaction(WorkflowBufferFactory factory, HashFactory
7069
HashMappingCoordinator.build(this::retrieveBlobData, this::writeBlobData);
7170
}
7271

73-
private Map<String, List<byte[]>> retrieveBlobData(String instanceId) {
74-
Map<String, Map<Integer, byte[]>> result = new HashMap<>();
72+
private Map<String, Map<String, byte[]>> retrieveBlobData(String instanceId) {
73+
Map<String, Map<String, byte[]>> result = new HashMap<>();
7574
for (Map.Entry<String, byte[]> entry : blobData(instanceId).entrySet()) {
7675
String[] splitted = entry.getKey().split(SEPARATOR);
77-
result
78-
.computeIfAbsent(splitted[0], __ -> new HashMap<>())
79-
.put(Integer.parseInt(splitted[1]), entry.getValue());
76+
result.computeIfAbsent(splitted[0], __ -> new HashMap<>()).put(splitted[1], entry.getValue());
8077
}
81-
return PersistenceUtils.mapMapToMapList(result);
78+
return result;
8279
}
8380

8481
private void writeBlobData(Map<String, List<HashMappingInfo>> writeInfo) {
@@ -99,7 +96,7 @@ public void removeProcessInstance(WorkflowContextData workflowContext) {
9996
super.removeProcessInstance(workflowContext);
10097
String instanceId = workflowContext.instanceData().id();
10198
removeBlobData(instanceId);
102-
hashCoordinator.afterRemove(instanceId);
99+
HashMappingCoordinator.afterRemove(instanceId);
103100
}
104101

105102
@Override
@@ -280,10 +277,10 @@ private PersistenceTaskInfo readVersion0(WorkflowInputBuffer buffer) {
280277

281278
private void writeLargeObject(
282279
HashItem item, WorkflowInstanceData instanceData, WorkflowOutputBuffer writer, byte[] bytes) {
283-
int index = hashCoordinator.calculateIndex(instanceData.id(), item, bytes);
280+
String index = hashCoordinator.calculateIndex(instanceData.id(), item, bytes);
284281
writer.writeByte(item.id());
285282
item.writeKey(writer);
286-
writer.writeShort((short) index);
283+
writer.writeString(index);
287284
}
288285

289286
private Object readLargeObject(String instanceId, WorkflowInputBuffer buffer) {
@@ -295,7 +292,7 @@ private Object readLargeObject(String instanceId, WorkflowInputBuffer buffer) {
295292
bufferFactory.input(
296293
new ByteArrayInputStream(
297294
hashCoordinator
298-
.readBytes(instanceId, item, buffer.readShort())
295+
.readBytes(instanceId, item, buffer.readString())
299296
.orElseThrow()))) {
300297
return input.readObject();
301298
}

‎impl/persistence/tests/src/main/java/io/serverlessworkflow/impl/persistence/test/AbstractHandlerPersistenceTest.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import io.serverlessworkflow.impl.executors.TransitionInfo;
3838
import io.serverlessworkflow.impl.persistence.PersistenceInstanceHandlers;
3939
import io.serverlessworkflow.impl.persistence.WorkflowPersistenceInstance;
40+
import io.serverlessworkflow.impl.persistence.hashing.HashMappingCoordinator;
4041
import java.io.IOException;
4142
import java.time.Duration;
4243
import java.time.Instant;
@@ -163,9 +164,12 @@ void testWorkflowInstance() throws InterruptedException {
163164
assertThat(stream.count()).isEqualTo(1);
164165
}
165166
definition.close();
167+
166168
instance =
167169
(WorkflowPersistenceInstance)
168170
handlers.reader().find(definition, workflowInstance.id()).orElseThrow();
171+
172+
HashMappingCoordinator.afterRemove(instance.id());
169173
updateWContext = mock(WorkflowContext.class);
170174
updateTContext = mock(TaskContext.class);
171175
when(updateTContext.position()).thenReturn(position2);

0 commit comments

Comments
 (0)