Package voldemort.store.memory

Source Code of voldemort.store.memory.InMemoryStorageEngine$InMemoryIterator

/*
* Copyright 2008-2009 LinkedIn, 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 voldemort.store.memory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.log4j.Logger;

import voldemort.VoldemortException;
import voldemort.annotations.concurrency.NotThreadsafe;
import voldemort.store.AbstractStorageEngine;
import voldemort.store.StoreUtils;
import voldemort.utils.ClosableIterator;
import voldemort.utils.Pair;
import voldemort.utils.Utils;
import voldemort.versioning.ObsoleteVersionException;
import voldemort.versioning.Occurred;
import voldemort.versioning.Version;
import voldemort.versioning.Versioned;

/**
* A simple non-persistent, in-memory store. Useful for unit testing.
*
* TODO Rewrite this class using striped locks for more granular locking.
*
*/
public class InMemoryStorageEngine<K, V, T> extends AbstractStorageEngine<K, V, T> {

    private static final Logger logger = Logger.getLogger(InMemoryStorageEngine.class);
    protected final ConcurrentMap<K, List<Versioned<V>>> map;

    public InMemoryStorageEngine(String name) {
        super(name);
        this.map = new ConcurrentHashMap<K, List<Versioned<V>>>();
    }

    public InMemoryStorageEngine(String name, ConcurrentMap<K, List<Versioned<V>>> map) {
        super(name);
        this.map = Utils.notNull(map);
    }

    public synchronized void deleteAll() {
        this.map.clear();
    }

    public boolean delete(K key) {
        return delete(key, null);
    }

    @Override
    public synchronized boolean delete(K key, Version version) {
        StoreUtils.assertValidKey(key);

        List<Versioned<V>> values = map.get(key);
        if(values == null) {
            return false;
        }

        if(version == null) {
            map.remove(key);
            return true;
        }

        boolean deletedSomething = false;
        Iterator<Versioned<V>> iterator = values.iterator();
        while(iterator.hasNext()) {
            Versioned<V> item = iterator.next();
            if(item.getVersion().compare(version) == Occurred.BEFORE) {
                iterator.remove();
                deletedSomething = true;
            }
        }
        if(values.size() == 0) {
            // if there are no more versions left, also remove the key from the
            // map
            map.remove(key);
        }

        return deletedSomething;
    }

    @Override
    public List<Version> getVersions(K key) {
        return StoreUtils.getVersions(get(key, null));
    }

    @Override
    public synchronized List<Versioned<V>> get(K key, T transform) throws VoldemortException {
        StoreUtils.assertValidKey(key);
        List<Versioned<V>> results = map.get(key);
        if(results == null) {
            return new ArrayList<Versioned<V>>(0);
        } else {
            return new ArrayList<Versioned<V>>(results);
        }
    }

    @Override
    public Map<K, List<Versioned<V>>> getAll(Iterable<K> keys, Map<K, T> transforms)
            throws VoldemortException {
        StoreUtils.assertValidKeys(keys);
        return StoreUtils.getAll(this, keys, transforms);
    }

    @Override
    public synchronized void put(K key, Versioned<V> value, T transforms) throws VoldemortException {
        StoreUtils.assertValidKey(key);
        List<Versioned<V>> items = map.get(key);
        // If we have no value, add the current value
        if(items == null) {
            items = new ArrayList<Versioned<V>>();
        }
        // Check for existing versions - remember which items to
        // remove in case of success
        List<Versioned<V>> itemsToRemove = new ArrayList<Versioned<V>>(items.size());
        for(Versioned<V> versioned: items) {
            Occurred occurred = value.getVersion().compare(versioned.getVersion());
            if(occurred == Occurred.BEFORE) {
                throw new ObsoleteVersionException("Obsolete version for key '" + key + "': "
                                                   + value.getVersion());
            } else if(occurred == Occurred.AFTER) {
                itemsToRemove.add(versioned);
            }
        }
        items.removeAll(itemsToRemove);
        items.add(value);
        map.put(key, items);
    }

    @Override
    public synchronized List<Versioned<V>> multiVersionPut(K key, final List<Versioned<V>> values) {
        // TODO the day this class implements getAndLock and putAndUnlock, this
        // method can be removed
        StoreUtils.assertValidKey(key);
        List<Versioned<V>> obsoleteVals = null;
        List<Versioned<V>> valuesInStorage = null;
        valuesInStorage = map.get(key);
        if(valuesInStorage == null) {
            valuesInStorage = new ArrayList<Versioned<V>>(values.size());
        }
        obsoleteVals = resolveAndConstructVersionsToPersist(valuesInStorage, values);
        map.put(key, valuesInStorage);
        return obsoleteVals;
    }

    @Override
    public ClosableIterator<Pair<K, Versioned<V>>> entries() {
        return new InMemoryIterator<K, V, T>(map, this);
    }

    @Override
    public ClosableIterator<K> keys() {
        // TODO Implement more efficient version.
        return StoreUtils.keys(entries());
    }

    @Override
    public ClosableIterator<Pair<K, Versioned<V>>> entries(int partition) {
        throw new UnsupportedOperationException("Partition based entries scan not supported for this storage type");
    }

    @Override
    public ClosableIterator<K> keys(int partition) {
        throw new UnsupportedOperationException("Partition based key scan not supported for this storage type");
    }

    @Override
    public synchronized void truncate() {
        map.clear();
    }

    @Override
    public String toString() {
        return toString(15);
    }

    public String toString(int size) {
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        int count = 0;
        for(Entry<K, List<Versioned<V>>> entry: map.entrySet()) {
            if(count > size) {
                builder.append("...");
                break;
            }
            builder.append(entry.getKey());
            builder.append(':');
            builder.append(entry.getValue());
            builder.append(',');
        }
        builder.append('}');
        return builder.toString();
    }

    /**
     * This class relies on the concurrent hash map's iterator to return a
     * weakly consistent view of the data in the map.
     */
    @NotThreadsafe
    private static class InMemoryIterator<K, V, T> implements
            ClosableIterator<Pair<K, Versioned<V>>> {

        private final Iterator<Entry<K, List<Versioned<V>>>> iterator;
        private K currentKey;
        private Iterator<Versioned<V>> currentValues;
        private InMemoryStorageEngine<K, V, T> inMemoryStorageEngine;

        public InMemoryIterator(ConcurrentMap<K, List<Versioned<V>>> map,
                                InMemoryStorageEngine<K, V, T> inMemoryStorageEngine) {
            this.iterator = map.entrySet().iterator();
            this.inMemoryStorageEngine = inMemoryStorageEngine;
        }

        @Override
        public boolean hasNext() {
            return hasNextInCurrentValues() || iterator.hasNext();
        }

        private boolean hasNextInCurrentValues() {
            return currentValues != null && currentValues.hasNext();
        }

        private Pair<K, Versioned<V>> nextInCurrentValues() {
            Versioned<V> item = currentValues.next();
            return Pair.create(currentKey, item);
        }

        @Override
        public Pair<K, Versioned<V>> next() {
            if(hasNextInCurrentValues()) {
                return nextInCurrentValues();
            } else {
                // keep trying to get a next, until we find one (they could get
                // removed)
                while(true) {
                    Entry<K, List<Versioned<V>>> entry = iterator.next();

                    List<Versioned<V>> list = entry.getValue();
                    synchronized(this.inMemoryStorageEngine) {
                        // okay we may have gotten an empty list, if so try
                        // again
                        if(list.size() == 0)
                            continue;

                        // grab a snapshot of the list while we have exclusive
                        // access
                        currentValues = new ArrayList<Versioned<V>>(list).iterator();
                    }
                    currentKey = entry.getKey();
                    return nextInCurrentValues();
                }
            }
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("No removal y'all.");
        }

        @Override
        public void close() {
            // nothing to do here
        }
    }
}
TOP

Related Classes of voldemort.store.memory.InMemoryStorageEngine$InMemoryIterator

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.