@Override public boolean contains(@Nullable Object object) { if (object instanceof Entry) { Entry<?, ?> entry = (Entry<?, ?>) object; return multimap.containsEntry(entry.getKey(), entry.getValue()); } return false; }
@VisibleForTesting static ImmutableSetMultimap<PartitionKeyToTraceId, Long> entriesThatIncreaseGap( ConcurrentMap<PartitionKeyToTraceId, Pair<Long>> sharedState, ImmutableSetMultimap<PartitionKeyToTraceId, Long> updates) { ImmutableSet.Builder<PartitionKeyToTraceId> toUpdate = ImmutableSet.builder(); // Enter a loop that affects shared state when an update widens the time interval for a key. for (Map.Entry<PartitionKeyToTraceId, Long> input : updates.entries()) { PartitionKeyToTraceId key = input.getKey(); long timestamp = input.getValue(); for (; ; ) { Pair<Long> oldRange = sharedState.get(key); if (oldRange == null) { // Initial state is where this key has a single timestamp. oldRange = sharedState.putIfAbsent(key, Pair.create(timestamp, timestamp)); // If there was no previous value, we need to update the index if (oldRange == null) { toUpdate.add(key); break; } } long first = timestamp < oldRange._1 ? timestamp : oldRange._1; long last = timestamp > oldRange._2 ? timestamp : oldRange._2; Pair<Long> newRange = Pair.create(first, last); if (oldRange.equals(newRange)) { break; // the current timestamp is contained } else if (sharedState.replace(key, oldRange, newRange)) { toUpdate.add(key); // The range was extended break; } } } // When the loop completes, we'll know one of our updates widened the interval of a trace, if // it is the first or last timestamp. By ignoring those between an existing interval, we can // end up with less Cassandra writes. Builder<PartitionKeyToTraceId, Long> result = ImmutableSetMultimap.builder(); for (PartitionKeyToTraceId needsUpdate : toUpdate.build()) { Pair<Long> firstLast = sharedState.get(needsUpdate); if (updates.containsEntry(needsUpdate, firstLast._1)) result.put(needsUpdate, firstLast._1); if (updates.containsEntry(needsUpdate, firstLast._2)) result.put(needsUpdate, firstLast._2); } return result.build(); }