All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bazaarvoice.emodb.sor.api.Compaction Maven / Gradle / Ivy

The newest version!
package com.bazaarvoice.emodb.sor.api;

import com.bazaarvoice.emodb.common.json.deferred.LazyJsonMap;
import com.bazaarvoice.emodb.sor.delta.Delta;
import com.bazaarvoice.emodb.sor.delta.Deltas;
import com.bazaarvoice.emodb.sor.delta.deser.DeltaParser;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableSet;

import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.hash;

/**
 * Placeholder for adjacent deltas that have been consolidated into a single
 * update to achieve a more compact representation in the data store.
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public final class Compaction {

    /** Number of old consistent deltas deleted by compaction. */
    private final long _count;

    /** UUID of the oldest consistent delta deleted by compaction. */
    private final UUID _first;

    /** UUID of the oldest consistent delta not deleted by compaction. */
    private final UUID _cutoff;

    /** The 'signature' intrinsic field of the object as of the cutoff UUID. */
    private final String _cutoffSignature;

    /** This holds the compacted delta, instead of referring to a cutoff delta. */
    private Delta _compactedDelta;

    private Set _lastTags;

    /**
     * UUID of the most recent consistent delta which changed the resolved object deleted by compaction.  Any delta
     * between this and the cutoff resolve to the same content, excluding intrinsics such as version and signature.
     */
     private final UUID _lastContentMutation;

    /**
     * Like {@link #_lastContentMutation} except this is the UUID of the most consistent delta which changed the
     * resolved object or its metadata (namely, the event tags).  Any delta between this and the cutoff do not need to
     * be posted to the databus because they are redundant to the subscriber.  For example, assume an update is made
     * at time t1 with tags ["alpha"].  Later, at time t2 a no-op update .. is made with tags ["beta"].
     * This second update would change _lastMutation but not _lastContentMutation.  Finally,
     * a third no-op delta at time t3 with the same tags as the previous update, ["beta"], would change neither
     * _lastMutation nor _lastContentMutation.
     */
    private final UUID _lastMutation;

    public Compaction(long count,
                      @Nullable UUID first,
                      @Nullable UUID cutoff,
                      @Nullable String cutoffSignature,
                      @Nullable UUID lastContentMutation,
                      @Nullable UUID lastMutation) {
        this(count, first, cutoff, cutoffSignature, lastContentMutation, lastMutation, (Delta) null, null);
    }

    public Compaction(long count,
                      @Nullable UUID first,
                      @Nullable UUID cutoff,
                      @Nullable String cutoffSignature,
                      @Nullable UUID lastContentMutation,
                      @Nullable UUID lastMutation,
                      Delta compactedDelta) {
        this(count, first, cutoff, cutoffSignature, lastContentMutation, lastMutation, compactedDelta, null);
    }

    public Compaction(long count,
                      @Nullable UUID first,
                      @Nullable UUID cutoff,
                      @Nullable String cutoffSignature,
                      @Nullable UUID lastContentMutation,
                      @Nullable UUID lastMutation,
                      @Nullable Delta compactedDelta,
                      @Nullable Set lastTags) {
        this(count, first, cutoff, cutoffSignature, lastContentMutation, lastMutation, lastTags);
        _compactedDelta = compactedDelta;
    }

    /**
     * Compactions are most commonly deserialized when a record contains one or more compaction records.  If there
     * is more than one all but the algorithmically selected compaction record are ignored.  As an efficiency gain
     * the compacted delta may be lazily deserialized so that resolution only occurs on the selected record.
     */
    @JsonCreator
    private Compaction(@JsonProperty("count") long count,
                       @JsonProperty("first") @Nullable UUID first,
                       @JsonProperty("cutoff") @Nullable UUID cutoff,
                       @JsonProperty("cutoffSignature") @Nullable String cutoffSignature,
                       @JsonProperty("lastContentMutation") @Nullable UUID lastContentMutation,
                       @JsonProperty("lastMutation") @Nullable UUID lastMutation,
                       @JsonProperty("compactedDelta") @Nullable String compactedDeltaString,
                       @JsonProperty("lastTags") @Nullable Set lastTags) {
        this(count, first, cutoff, cutoffSignature, lastContentMutation, lastMutation, lastTags);

        if (compactedDeltaString != null) {
            // By definition the compacted delta must be constant.  If the literal is a map then there are many
            // circumstances where performance is improved by lazily converting the literal to a JSON map, such as when
            // the literal will be streamed as-is to an API request.  Therefore create a literal delta from a lazy map.

            // Shouldn't be any leading white space, but better to be careful.
            for (int i=0; i < compactedDeltaString.length(); i++) {
                if (!Character.isWhitespace(compactedDeltaString.charAt(i))) {
                    if (compactedDeltaString.charAt(i) == '{') {
                        _compactedDelta = Deltas.literal(new LazyJsonMap(compactedDeltaString));
                    } else {
                        _compactedDelta = DeltaParser.parse(compactedDeltaString);
                    }
                    break;
                }
            }
        }
    }

    public Compaction(long count,
                      @Nullable UUID first,
                      @Nullable UUID cutoff,
                      @Nullable String cutoffSignature,
                      @Nullable UUID lastContentMutation,
                      @Nullable UUID lastMutation,
                      @Nullable Set lastTags) {
        checkArgument((count > 0) || (first == null && cutoff == null));
        checkArgument((count == 0) || (first != null && cutoff != null));
        checkArgument((cutoff != null) == (cutoffSignature != null));
        _count = count;
        _first = first;
        _cutoff = cutoff;
        _cutoffSignature = cutoffSignature;
        // For historical reasons there may exist grandfathered-in compactions where the last mutation was recorded
        // but not the last content mutation.  In these cases substitute the last mutation if available
        _lastContentMutation = lastContentMutation != null ? lastContentMutation : lastMutation;
        _lastMutation = lastMutation;
        _lastTags = lastTags == null ? ImmutableSet.of() : lastTags;
    }


    public long getCount() {
        return _count;
    }

    public UUID getFirst() {
        return _first;
    }

    public UUID getLastContentMutation() {
        return _lastContentMutation;
    }

    public UUID getLastMutation() {
        return _lastMutation;
    }

    public UUID getCutoff() {
        return _cutoff;
    }

    public String getCutoffSignature() {
        return _cutoffSignature;
    }

    public Delta getCompactedDelta() {
        return _compactedDelta;
    }

    public boolean hasCompactedDelta() {
        return _compactedDelta != null;
    }

    /** Last applied tags */
    @Nullable
    public Set getLastTags() {
        return _lastTags;
    }

    /** For backwards compatibility, we need to do this **/
    public Compaction setCompactedDelta(Delta delta) {
        _compactedDelta = delta;
        return this;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Compaction)) {
            return false;
        }
        Compaction that = (Compaction) o;
        return _count == that._count &&
                Objects.equals(_first, that.getFirst()) &&
                Objects.equals(_cutoff, that.getCutoff()) &&
                Objects.equals(_cutoffSignature, that.getCutoffSignature()) &&
                Objects.equals(_lastMutation, that.getLastMutation()) &&
                Objects.equals(_lastContentMutation, that.getLastContentMutation());
    }

    @Override
    public int hashCode() {
        return hash(_count, _first, _cutoff, _cutoffSignature, _lastMutation, _lastContentMutation);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy