Package voldemort.store.configuration

Source Code of voldemort.store.configuration.ConfigurationStorageEngine$FilesIterator

/*
* 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.configuration;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import voldemort.VoldemortException;
import voldemort.store.AbstractStorageEngine;
import voldemort.store.StoreCapabilityType;
import voldemort.store.StoreUtils;
import voldemort.store.metadata.MetadataStore;
import voldemort.utils.ClosableIterator;
import voldemort.utils.Pair;
import voldemort.versioning.ObsoleteVersionException;
import voldemort.versioning.Occurred;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Version;
import voldemort.versioning.Versioned;

/**
* A FileSystem based Storage Engine to persist configuration metadata.<br>
* <imp>Used only by {@link MetadataStore}</imp><br>
*
*
*/
public class ConfigurationStorageEngine extends AbstractStorageEngine<String, String, String> {

    private final static Logger logger = Logger.getLogger(ConfigurationStorageEngine.class);
    private static final String VERSION_DIRECTORY = ".version";
    private static final String TEMP_DIRECTORY = ".temp";
    private final File directory;

    public ConfigurationStorageEngine(String name, String directory) {
        super(name);
        this.directory = new File(directory);
        if(!this.directory.exists() && this.directory.canRead())
            throw new IllegalArgumentException("Directory " + this.directory.getAbsolutePath()
                                               + " does not exist or can not be read.");
    }

    @Override
    public ClosableIterator<Pair<String, Versioned<String>>> entries() {
        List<String> fileNameList = new ArrayList<String>();
        for(String fileName: this.directory.list()) {
            if(fileName.equals(VERSION_DIRECTORY) || fileName.equals(TEMP_DIRECTORY)) {
                continue;
            }
            fileNameList.add(fileName);
        }
        return new FilesIterator(fileNameList, this);
    }

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

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

    @Override
    public synchronized boolean delete(String key, Version version) throws VoldemortException {
        StoreUtils.assertValidKey(key);
        for(File file: getDirectory(key).listFiles()) {
            if(file.getName().equals(key)) {
                try {
                    // delete the file and the version file
                    return file.delete()
                           && new File(getVersionDirectory(), file.getName()).delete();
                } catch(Exception e) {
                    logger.error("Error while attempt to delete key:" + key, e);
                }
            }
        }

        return false;
    }

    @Override
    public synchronized List<Versioned<String>> get(String key, String transforms)
            throws VoldemortException {
        StoreUtils.assertValidKey(key);
        return get(key, getDirectory(key).listFiles());
    }

    @Override
    public List<Version> getVersions(String key) {
        List<Versioned<String>> values = get(key, (String) null);
        List<Version> versions = new ArrayList<Version>(values.size());
        for(Versioned<?> value: values) {
            versions.add(value.getVersion());
        }
        return versions;
    }

    @Override
    public synchronized Map<String, List<Versioned<String>>> getAll(Iterable<String> keys,
                                                                    Map<String, String> transforms)
            throws VoldemortException {
        StoreUtils.assertValidKeys(keys);
        Map<String, List<Versioned<String>>> result = StoreUtils.newEmptyHashMap(keys);
        for(String key: keys) {
            List<Versioned<String>> values = get(key, getDirectory(key).listFiles());
            if(!values.isEmpty())
                result.put(key, values);
        }
        return result;
    }

    @Override
    public synchronized void put(String key, Versioned<String> value, String transforms)
            throws VoldemortException {
        StoreUtils.assertValidKey(key);

        if(null == value.getValue()) {
            throw new VoldemortException("metadata cannot be null !!");
        }
        // Check for obsolete version
        File[] files = getDirectory(key).listFiles();
        for(File file: files) {
            if(file.getName().equals(key)) {
                VectorClock clock = readVersion(key);
                if(value.getVersion().compare(clock) == Occurred.AFTER) {
                    // continue
                } else if(value.getVersion().compare(clock) == Occurred.BEFORE) {
                    throw new ObsoleteVersionException("A successor version " + clock
                                                       + "  to this " + value.getVersion()
                                                       + " exists for key " + key);
                } else if(value.getVersion().compare(clock) == Occurred.CONCURRENTLY) {
                    throw new ObsoleteVersionException("Concurrent Operation not allowed on Metadata.");
                }
            }
        }

        File keyFile = new File(getDirectory(key), key);
        VectorClock newClock = (VectorClock) value.getVersion();
        if(!keyFile.exists() || keyFile.delete()) {
            try {
                FileUtils.writeStringToFile(keyFile, value.getValue(), "UTF-8");
                writeVersion(key, newClock);
            } catch(IOException e) {
                throw new VoldemortException(e);
            }
        }
    }

    private File getDirectory(String key) {
        if(MetadataStore.OPTIONAL_KEYS.contains(key))
            return getTempDirectory();
        else
            return this.directory;
    }

    private List<Versioned<String>> get(String key, File[] files) {
        try {
            List<Versioned<String>> found = new ArrayList<Versioned<String>>();
            for(File file: files) {
                if(file.getName().equals(key)) {
                    VectorClock clock = readVersion(key);
                    if(null != clock) {
                        found.add(new Versioned<String>(FileUtils.readFileToString(file, "UTF-8"),
                                                        clock));
                    }
                }
            }
            return found;
        } catch(IOException e) {
            throw new VoldemortException(e);
        }
    }

    private VectorClock readVersion(String key) {
        try {
            File versionFile = new File(getVersionDirectory(), key);
            if(!versionFile.exists()) {
                // bootstrap file save default clock as version.
                VectorClock clock = new VectorClock(0);
                writeVersion(key, clock);
                return clock;
            } else {
                // read the version file and return version.
                String hexCode = FileUtils.readFileToString(versionFile, "UTF-8");
                return new VectorClock(Hex.decodeHex(hexCode.toCharArray()));
            }
        } catch(Exception e) {
            throw new VoldemortException("Failed to read Version for Key:" + key, e);
        }
    }

    private void writeVersion(String key, VectorClock version) {
        try {
            File versionFile = new File(getVersionDirectory(), key);
            if(!versionFile.exists() || versionFile.delete()) {
                // write the version file.
                String hexCode = new String(Hex.encodeHex(version.toBytes()));
                FileUtils.writeStringToFile(versionFile, hexCode, "UTF-8");
            }
        } catch(Exception e) {
            throw new VoldemortException("Failed to write Version for Key:" + key, e);
        }
    }

    private File getVersionDirectory() {
        File versionDir = new File(this.directory, VERSION_DIRECTORY);
        if(!versionDir.exists() || !versionDir.isDirectory()) {
            versionDir.delete();
            versionDir.mkdirs();
        }

        return versionDir;
    }

    private File getTempDirectory() {
        File tempDir = new File(this.directory, TEMP_DIRECTORY);
        if(!tempDir.exists() || !tempDir.isDirectory()) {
            tempDir.delete();
            tempDir.mkdirs();
        }

        return tempDir;
    }

    @Override
    public Object getCapability(StoreCapabilityType capability) {
        throw new VoldemortException("No extra capability.");
    }

    @Override
    public ClosableIterator<String> keys() {
        throw new VoldemortException("keys iteration not supported.");
    }

    @Override
    public void truncate() {
        throw new VoldemortException("Truncate not supported in ConfigurationStorageEngine");
    }

    private static class FilesIterator implements ClosableIterator<Pair<String, Versioned<String>>> {

        private final Iterator<String> iterator;
        private final ConfigurationStorageEngine storageEngineRef;

        public FilesIterator(List<String> fileNames, ConfigurationStorageEngine storageEngine) {
            iterator = fileNames.iterator();
            storageEngineRef = storageEngine;
        }

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

        @Override
        public Pair<String, Versioned<String>> next() {
            String fileName = iterator.next();
            Pair<String, Versioned<String>> nextValue = null;
            if(fileName != null) {
                String key = fileName;
                List<Versioned<String>> resultStringList = this.storageEngineRef.get(key, "");
                if(resultStringList != null && resultStringList.size() > 0) {
                    nextValue = Pair.create(key, resultStringList.get(0));
                }
            }

            return nextValue;
        }

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

        @Override
        public void close() {}

    }

}
TOP

Related Classes of voldemort.store.configuration.ConfigurationStorageEngine$FilesIterator

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.