Package com.netflix.zeno.diff.history

Source Code of com.netflix.zeno.diff.history.DiffHistoryTracker

/*
*
*  Copyright 2013 Netflix, Inc.
*
*     Licensed under the Apache License, Version 2.0 (the "License");
*     you may not use this file except in compliance with the License.
*     You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*     Unless required by applicable law or agreed to in writing, software
*     distributed under the License is distributed on an "AS IS" BASIS,
*     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*     See the License for the specific language governing permissions and
*     limitations under the License.
*
*/
package com.netflix.zeno.diff.history;

import com.netflix.zeno.diff.DiffInstruction;
import com.netflix.zeno.diff.TypeDiffInstruction;
import com.netflix.zeno.fastblob.FastBlobStateEngine;
import com.netflix.zeno.util.SimultaneousExecutor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* A data structure to track the history of changes in a single FastBlobStateEngine.<p/>
*
* Each time the state engine consumes a blob file, call "addState()".  Then, at any time, pass in a key for an object identified in the
* TypeDiffInstruction to retrieve a historical record of that data.<p/>
*
* This data structure retains a history of all changes in a data set across some specified number of rolling updates.  Because this retains a
* large amount of data, it can consume a significant memory footprint, and resource availability should be planned accordingly.<p/>
*
* This class takes advantage of the guarantee that two identical objects across adjacent data states will be the same instance.  Comparisons
* can therefore be done with ==, rather than checking for identical serialized representations.
*
* @author dkoszewnik
*
*/
public class DiffHistoryTracker {

    private final int historySizeToKeep;
    private final FastBlobStateEngine stateEngine;
    private final LinkedList<DiffHistoricalState> historicalStates;
    private final Map<String, Map<String, String>> historicalStateHeaderTags;
    private final TypeDiffInstruction<?> typeDiffInstructions[];
    private DiffHistoryDataState currentDataState;

    /**
     *
     * @param numStatesToKeep - The number of historical states to keep
     * @param stateEngine - The state engine to track the history of
     * @param diffInstruction - The set of key extractions for types in the object model.
     */
    public DiffHistoryTracker(int numStatesToKeep, FastBlobStateEngine stateEngine, DiffInstruction diffInstruction) {
        this.historySizeToKeep = numStatesToKeep;
        this.stateEngine = stateEngine;
        this.historicalStates = new LinkedList<DiffHistoricalState>();
        this.historicalStateHeaderTags = new ConcurrentHashMap<String, Map<String,String>>();
        this.typeDiffInstructions = diffInstruction.getTypeInstructions();
    }

    /**
     * Call this method after new data has been loaded by the FastBlobStateEngine.  This will add a historical record
     * of the differences between the previous state and this new state.
     */
    public void addState() {
        DiffHistoryDataState nextState = new DiffHistoryDataState(stateEngine, typeDiffInstructions);

        if(currentDataState != null)
            newHistoricalState(currentDataState, nextState);

        currentDataState = nextState;
    }

    private void newHistoricalState(final DiffHistoryDataState from, final DiffHistoryDataState to) {
        final DiffHistoricalState historicalState = new DiffHistoricalState(to.getVersion());

        SimultaneousExecutor executor = new SimultaneousExecutor();

        for(final TypeDiffInstruction<?> typeInstruction : from.getTypeDiffInstructions()) {
            executor.execute(new Runnable() {
                public void run() {
                    Map<Object, Object> fromTypeState = from.getTypeState(typeInstruction.getTypeIdentifier());
                    Map<Object, Object> toTypeState = to.getTypeState(typeInstruction.getTypeIdentifier());

                    historicalState.addTypeState(typeInstruction, fromTypeState, toTypeState);
                }
            });
        }

        executor.awaitUninterruptibly();

        historicalStates.addFirst(historicalState);
        historicalStateHeaderTags.put(to.getVersion(), new HashMap<String, String>(stateEngine.getHeaderTags()));

        /// trim historical entries beyond desired size.
        if(historicalStates.size() > historySizeToKeep) {
            DiffHistoricalState removedState = historicalStates.removeLast();
            historicalStateHeaderTags.remove(removedState.getVersion());
        }
    }

    /**
     * Return the history of the object identified by the supplied type / key combination.<p/>
     *
     * The returned list will contain one entry for each state in the rolling history retained by this DiffHistoryTracker.
     * The latest entry will be at index 0, and the earliest entry will be the last in the list.  Not all entries in the returned
     * list must reflect a transition; an entry is included in the list whether or not the instance changed for a given state.
     *
     */
    public <T> List<DiffObjectHistoricalTransition<T>> getObjectHistory(String type, Object key) {
        List<DiffObjectHistoricalTransition<T>> states = new ArrayList<DiffObjectHistoricalTransition<T>>(historicalStates.size());
        Map<Object, T> typeState = currentDataState.getTypeState(type);

        /// start with the currently available item (if available)
        T currentItem = typeState.get(key);

        /// and work backwards through history.
        for(DiffHistoricalState state : historicalStates) {

            DiffHistoricalTypeState<Object, T> historicalState = state.getTypeState(type);

            Map<Object, T> diffObjects = historicalState.getDiffObjects();
            Map<Object, T> deletedObjects = historicalState.getDeletedObjects();
            Set<Object> newObjects = historicalState.getNewObjects();

            T previous;

            if(diffObjects.containsKey(key)) {
                previous = diffObjects.get(key);
            } else if(deletedObjects.containsKey(key)) {
                previous = deletedObjects.get(key);
            } else if(newObjects.contains(key)) {
                previous = null;
            } else {
                previous = currentItem;
            }

            /// adding the from -> to objects (whether identical or not) to a list.
            states.add(new DiffObjectHistoricalTransition<T>(state.getVersion(), previous, currentItem));
            currentItem = previous;
        }

        return states;
    }

    /**
     * Returns a list of the historical states, starting with the most recent and ending with the oldest.
     */
    public List<DiffHistoricalState> getHistoricalStates() {
        return Collections.unmodifiableList(historicalStates);
    }

    /**
     * Returns the header tags which were attached to the given version.
     */
    public Map<String, String> getHistoricalStateHeaderTags(String stateVersion) {
        return historicalStateHeaderTags.get(stateVersion);
    }

}
TOP

Related Classes of com.netflix.zeno.diff.history.DiffHistoryTracker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.