2020import cz .o2 .proxima .core .functional .UnaryFunction ;
2121import cz .o2 .proxima .core .repository .AttributeDescriptor ;
2222import cz .o2 .proxima .core .repository .EntityDescriptor ;
23+ import cz .o2 .proxima .core .storage .StreamElement ;
2324import cz .o2 .proxima .core .util .Pair ;
2425import cz .o2 .proxima .internal .com .google .common .annotations .VisibleForTesting ;
2526import java .io .Serializable ;
2829import java .util .Map ;
2930import java .util .NavigableMap ;
3031import java .util .Objects ;
32+ import java .util .Optional ;
3133import java .util .Set ;
3234import java .util .TreeMap ;
3335import java .util .concurrent .atomic .AtomicBoolean ;
@@ -44,8 +46,7 @@ class TimeBoundedVersionedCache implements Serializable {
4446
4547 @ Value
4648 static class Payload {
47- @ Nullable Object data ;
48- long seqId ;
49+ StreamElement data ;
4950 boolean overridable ;
5051 }
5152
@@ -63,7 +64,6 @@ static class Payload {
6364
6465 @ Nullable
6566 synchronized Pair <Long , Payload > get (String key , String attribute , long stamp ) {
66-
6767 NavigableMap <String , NavigableMap <Long , Payload >> attrMap ;
6868 attrMap = cache .get (key );
6969 if (attrMap != null ) {
@@ -107,16 +107,15 @@ synchronized void scan(
107107 return ;
108108 }
109109 String lastParent = null ;
110- Pair <Long , Payload > parentEntry = null ;
110+ Pair <Long , Payload > parentEntry ;
111111 long parentTombstoneStamp = stamp ;
112112 for (Map .Entry <String , NavigableMap <Long , Payload >> e : attrMap .tailMap (offset ).entrySet ()) {
113-
114113 if (e .getKey ().startsWith (prefix )) {
115114 if (!e .getKey ().equals (offset )) {
116115 if (lastParent == null || !e .getKey ().startsWith (lastParent )) {
117116 lastParent = parentRecordExtractor .apply (e .getKey ());
118117 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 () ;
120119 parentTombstoneStamp = isDelete ? parentEntry .getFirst () : -1 ;
121120 }
122121 Map .Entry <Long , Payload > floorEntry = e .getValue ().floorEntry (stamp );
@@ -194,45 +193,56 @@ synchronized void keys(int offset, int limit, Consumer<String> keyConsumer) {
194193 }
195194 }
196195
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 ) {
205197 AtomicBoolean updated = new AtomicBoolean ();
206198 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 ));
229201 return updated .get ();
230202 }
231203
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 ) {
234242
235243 if (log .isDebugEnabled ()) {
244+ String key = element .getKey ();
245+ Object value = element .getParsed ().orElse (null );
236246 AttributeDescriptor <Object > attrDesc = entity .findAttribute (attribute , true ).orElse (null );
237247 if (attrDesc != null ) {
238248 log .debug (
0 commit comments