org.kiji.mapreduce.KeyValueStoreReaderFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.kiji.mapreduce.KeyValueStoreReaderFactory.java

Source

/**
 * (c) Copyright 2012 WibiData, Inc.
 *
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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 org.kiji.mapreduce;

import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class that manages the creation of KeyValueStoreReaders associated
 * with a set of bound KeyValueStore name--instance pairs.
 *
 * <p>This also manages a cache of opened readers, which will be returned
 * if available, rather than creating a new store reader for a given named
 * store.</p>
 */
public class KeyValueStoreReaderFactory implements Closeable {
    private static final Logger LOG = LoggerFactory.getLogger(KeyValueStoreReaderFactory.class.getName());

    /** The set of Key-value stores to provide to the KeyValueStoreClient. */
    private final Map<String, KeyValueStore<?, ?>> mKeyValueStores;

    /** A cache of opened key-value stores we may use and modify. */
    private final Map<String, KeyValueStoreReader<?, ?>> mStoreReaders;

    /** Creates an empty KeyValueStoreReaderFactory. */
    public KeyValueStoreReaderFactory() {
        this(Collections.<String, KeyValueStore<?, ?>>emptyMap());
    }

    /**
     * Creates a KeyValueStoreReaderFactory.
     *
     * @param storeBindings defines the set of KeyValueStores available, and the
     *     names by which they are registered.
     */
    public KeyValueStoreReaderFactory(Map<String, KeyValueStore<?, ?>> storeBindings) {
        mKeyValueStores = Collections.unmodifiableMap(storeBindings);
        mStoreReaders = Collections.synchronizedMap(new HashMap<String, KeyValueStoreReader<?, ?>>());
    }

    /**
     * Creates a KeyValueStoreReaderFactory.
     *
     * @param conf the Configuration from which a set of KeyValueStore bindings should
     *     be deserialized and initialized.
     * @throws IOException if there is an error deserializing or initializing a
     *     KeyValueStore instance.
     */
    public KeyValueStoreReaderFactory(Configuration conf) throws IOException {
        Map<String, KeyValueStore<?, ?>> keyValueStores = new HashMap<String, KeyValueStore<?, ?>>();
        int numKvStores = conf.getInt(KeyValueStore.CONF_KEY_VALUE_STORE_COUNT,
                KeyValueStore.DEFAULT_KEY_VALUE_STORE_COUNT);
        for (int i = 0; i < numKvStores; i++) {
            KeyValueStoreConfiguration kvStoreConf = new KeyValueStoreConfiguration(conf, i);

            Class<? extends KeyValueStore> kvStoreClass = kvStoreConf
                    .<KeyValueStore>getClass(KeyValueStore.CONF_CLASS, null, KeyValueStore.class);

            String kvStoreName = kvStoreConf.get(KeyValueStore.CONF_NAME, "");

            if (null != kvStoreClass) {
                KeyValueStore<?, ?> kvStore = ReflectionUtils.newInstance(kvStoreClass, conf);
                if (null != kvStore) {
                    kvStore.initFromConf(kvStoreConf);
                    if (kvStoreName.isEmpty()) {
                        LOG.warn("Deserialized KeyValueStore not bound to a name; ignoring.");
                        continue;
                    }
                    keyValueStores.put(kvStoreName, kvStore);
                }
            }
        }

        mKeyValueStores = Collections.unmodifiableMap(keyValueStores);
        mStoreReaders = Collections.synchronizedMap(new HashMap<String, KeyValueStoreReader<?, ?>>());
    }

    /** {@inheritDoc} */
    @Override
    public void close() throws IOException {
        for (KeyValueStoreReader<?, ?> reader : mStoreReaders.values()) {
            if (null != reader && reader.isOpen()) {
                IOUtils.closeQuietly(reader);
            }
        }
    }

    /**
     * Opens a KeyValueStore associated with storeName for read-access.
     *
     * <p>You should close() the store instance returned by this method
     * when you are done with it. (Or close this KeyValueStoreReaderFactory
     * when you are done with all stores.)</p>
     *
     * <p>Calling getStore() multiple times on the same name will reuse the same
     * reader unless it is closed.</p>
     *
     * @param <K> The key type for the KeyValueStore.
     * @param <V> The value type for the KeyValueStore.
     * @param storeName the name of the KeyValueStore to open.
     * @return A KeyValueStoreReader associated with this storeName, or null
     *     if there is no such KeyValueStore available.
     * @throws IOException if there is an error opening the underlying storage resource.
     * @throws InterruptedException if there is an interruption while connecting to
     *     the underlying storage resource.
     */
    @SuppressWarnings("unchecked")
    public <K, V> KeyValueStoreReader<K, V> getStore(String storeName) throws IOException, InterruptedException {
        assert null != mStoreReaders && null != mKeyValueStores;
        if (null == mStoreReaders.get(storeName) || !mStoreReaders.get(storeName).isOpen()) {
            // In the first case, add a store because none existed before,
            // in the second case, replace the store because this one has been closed.
            KeyValueStoreReader<K, V> reader = null;
            if (null != mKeyValueStores.get(storeName)) {
                KeyValueStore<K, V> store = (KeyValueStore<K, V>) mKeyValueStores.get(storeName);
                reader = store.open();
            }
            mStoreReaders.put(storeName, reader);
        }
        return (KeyValueStoreReader<K, V>) mStoreReaders.get(storeName);
    }

    @Override
    protected void finalize() throws Throwable {
        close();
        super.finalize();
    }
}