|
29 | 29 | import java.util.Map; |
30 | 30 | import java.util.NavigableMap; |
31 | 31 | import java.util.Objects; |
| 32 | +import java.util.Optional; |
32 | 33 | import java.util.Set; |
33 | 34 | import java.util.TreeMap; |
34 | 35 | import java.util.concurrent.atomic.AtomicBoolean; |
@@ -63,7 +64,6 @@ static class Payload { |
63 | 64 |
|
64 | 65 | @Nullable |
65 | 66 | synchronized Pair<Long, Payload> get(String key, String attribute, long stamp) { |
66 | | - |
67 | 67 | NavigableMap<String, NavigableMap<Long, Payload>> attrMap; |
68 | 68 | attrMap = cache.get(key); |
69 | 69 | if (attrMap != null) { |
@@ -107,16 +107,15 @@ synchronized void scan( |
107 | 107 | return; |
108 | 108 | } |
109 | 109 | String lastParent = null; |
110 | | - Pair<Long, Payload> parentEntry = null; |
| 110 | + Pair<Long, Payload> parentEntry; |
111 | 111 | long parentTombstoneStamp = stamp; |
112 | 112 | for (Map.Entry<String, NavigableMap<Long, Payload>> e : attrMap.tailMap(offset).entrySet()) { |
113 | | - |
114 | 113 | if (e.getKey().startsWith(prefix)) { |
115 | 114 | if (!e.getKey().equals(offset)) { |
116 | 115 | if (lastParent == null || !e.getKey().startsWith(lastParent)) { |
117 | 116 | lastParent = parentRecordExtractor.apply(e.getKey()); |
118 | 117 | parentEntry = lastParent == null ? null : get(key, lastParent, stamp); |
119 | | - boolean isDelete = parentEntry != null && parentEntry.getSecond().getData() == null; |
| 118 | + boolean isDelete = parentEntry != null && parentEntry.getSecond().getData().isDelete(); |
120 | 119 | parentTombstoneStamp = isDelete ? parentEntry.getFirst() : -1; |
121 | 120 | } |
122 | 121 | Map.Entry<Long, Payload> floorEntry = e.getValue().floorEntry(stamp); |
@@ -194,45 +193,56 @@ synchronized void keys(int offset, int limit, Consumer<String> keyConsumer) { |
194 | 193 | } |
195 | 194 | } |
196 | 195 |
|
197 | | - synchronized boolean put( |
198 | | - String key, |
199 | | - String attribute, |
200 | | - long stamp, |
201 | | - long sequentialId, |
202 | | - boolean overwrite, |
203 | | - @Nullable Object value) { |
204 | | - |
| 196 | + synchronized boolean put(StreamElement element, boolean overwrite) { |
205 | 197 | AtomicBoolean updated = new AtomicBoolean(); |
206 | 198 | cache.compute( |
207 | | - key, |
208 | | - (k, attrMap) -> { |
209 | | - if (attrMap == null) { |
210 | | - attrMap = new TreeMap<>(); |
211 | | - } |
212 | | - NavigableMap<Long, Payload> valueMap = |
213 | | - attrMap.computeIfAbsent(attribute, tmp -> new TreeMap<>()); |
214 | | - if (valueMap.isEmpty() || valueMap.firstKey() - keepDuration < stamp) { |
215 | | - final Payload oldPayload = valueMap.get(stamp); |
216 | | - if (overwrite || oldPayload == null || oldPayload.overridable) { |
217 | | - logPayloadUpdateIfNecessary(key, attribute, stamp, value); |
218 | | - Payload newPayload = new Payload(value, sequentialId, !overwrite); |
219 | | - valueMap.put(stamp, newPayload); |
220 | | - updated.set(!newPayload.equals(oldPayload)); |
221 | | - } |
222 | | - } |
223 | | - long first; |
224 | | - while (!valueMap.isEmpty() && (first = valueMap.firstKey()) + keepDuration < stamp) { |
225 | | - valueMap.remove(first); |
226 | | - } |
227 | | - return attrMap; |
228 | | - }); |
| 199 | + element.getKey(), |
| 200 | + (k, attrMap) -> updateAttrMapByElement(element, overwrite, updated, attrMap)); |
229 | 201 | return updated.get(); |
230 | 202 | } |
231 | 203 |
|
232 | | - private void logPayloadUpdateIfNecessary( |
233 | | - String key, String attribute, long stamp, @Nullable Object value) { |
| 204 | + private NavigableMap<String, NavigableMap<Long, Payload>> updateAttrMapByElement( |
| 205 | + StreamElement element, |
| 206 | + boolean overwrite, |
| 207 | + AtomicBoolean updated, |
| 208 | + @Nullable NavigableMap<String, NavigableMap<Long, Payload>> attrMap) { |
| 209 | + |
| 210 | + if (attrMap == null) { |
| 211 | + attrMap = new TreeMap<>(); |
| 212 | + } |
| 213 | + String attribute = |
| 214 | + element.isDeleteWildcard() |
| 215 | + ? element.getAttributeDescriptor().toAttributePrefix() |
| 216 | + : element.getAttribute(); |
| 217 | + long stamp = element.getStamp(); |
| 218 | + |
| 219 | + NavigableMap<Long, Payload> valueMap = |
| 220 | + attrMap.computeIfAbsent(attribute, tmp -> new TreeMap<>()); |
| 221 | + if (valueMap.isEmpty() || valueMap.firstKey() - keepDuration < stamp) { |
| 222 | + final Payload oldPayload = valueMap.get(stamp); |
| 223 | + if (overwrite || oldPayload == null || oldPayload.overridable) { |
| 224 | + logPayloadUpdateIfNecessary(attribute, stamp, element); |
| 225 | + Payload newPayload = new Payload(element, !overwrite); |
| 226 | + valueMap.put(stamp, newPayload); |
| 227 | + Object oldParsed = |
| 228 | + Optional.ofNullable(oldPayload == null ? null : oldPayload.getData()) |
| 229 | + .flatMap(StreamElement::getParsed) |
| 230 | + .orElse(null); |
| 231 | + updated.set(!element.getParsed().equals(oldParsed)); |
| 232 | + } |
| 233 | + } |
| 234 | + long first; |
| 235 | + while (!valueMap.isEmpty() && (first = valueMap.firstKey()) + keepDuration < stamp) { |
| 236 | + valueMap.remove(first); |
| 237 | + } |
| 238 | + return attrMap; |
| 239 | + } |
| 240 | + |
| 241 | + private void logPayloadUpdateIfNecessary(String attribute, long stamp, StreamElement element) { |
234 | 242 |
|
235 | 243 | if (log.isDebugEnabled()) { |
| 244 | + String key = element.getKey(); |
| 245 | + Object value = element.getParsed().orElse(null); |
236 | 246 | AttributeDescriptor<Object> attrDesc = entity.findAttribute(attribute, true).orElse(null); |
237 | 247 | if (attrDesc != null) { |
238 | 248 | log.debug( |
|
0 commit comments