Package io.fathom.cloud.blobs

Source Code of io.fathom.cloud.blobs.LocalFilesystemBlobStore

package io.fathom.cloud.blobs;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fathomdb.io.IoUtils;
import com.fathomdb.utils.Hex;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import com.google.protobuf.ByteString;

public class LocalFilesystemBlobStore extends BlobStoreBase {
    private static final Logger log = LoggerFactory.getLogger(LocalFilesystemBlobStore.class);

    public static class Factory implements BlobStoreFactory {
        final String baseDir;

        public Factory(String baseDir) {
            this.baseDir = baseDir;
        }

        @Override
        public BlobStore get(String key) throws IOException {
            Preconditions.checkArgument(!Strings.isNullOrEmpty(key));
            Preconditions.checkArgument(isSafeFileName(key));

            File dir = new File(baseDir, key);
            return new LocalFilesystemBlobStore(dir);
        }
    }

    final File basedir;
    final File tmpdir;
    final File queueDir;

    public LocalFilesystemBlobStore(File basedir) throws IOException {
        super();
        this.basedir = basedir;

        this.tmpdir = new File(basedir, "_tmp");
        IoUtils.mkdirs(this.tmpdir);

        this.queueDir = new File(basedir, "_queue");
    }

    public static boolean isSafeFileName(String key) {
        int len = key.length();
        for (int i = 0; i < len; i++) {
            char c = key.charAt(i);
            if (Character.isLetterOrDigit(c)) {
                continue;
            }

            switch (c) {
            case '_':
            case '-':
                break;

            default:
                return false;
            }
        }
        return true;
    }

    @Override
    public BlobData find(ByteString key) throws IOException {
        File file = buildFile(key);

        if (file.exists()) {
            return new BlobData(file, key);
        } else {
            return null;
        }
    }

    @Override
    public boolean has(ByteString key, boolean checkCache) {
        File file = buildFile(key);
        return file.exists();
    }

    private File buildFile(ByteString key, boolean mkdirs) throws IOException {
        File file = buildFile(key);

        if (mkdirs) {
            // TODO: Cache created / not created state?
            IoUtils.mkdirs(file.getParentFile());
        }

        return file;
    }

    private File buildFile(ByteString key) {
        File file = buildFile(basedir, key);
        return file;
    }

    @Override
    public void put(BlobData data) throws IOException {
        ByteString key = data.getHash();

        File file = buildFile(key, true);

        if (file.exists()) {
            // TODO: Verify that the file contents match??
            if (isSame(file, data)) {
                return;
            } else {
                throw new UnsupportedOperationException();
            }
        }

        try (TempFile tempFile = TempFile.in(tmpdir)) {
            tempFile.copyFrom(data);
            tempFile.renameTo(file);
        }
    }

    private boolean isSame(File a, BlobData b) throws IOException {
        ByteSource supplierA = Files.asByteSource(a);
        // ByteSource supplierB = ByteStreams.asByteSource(b);

        return supplierA.contentEquals(b);
    }

    @Override
    public Iterable<ByteString> listWithPrefix(String prefix) throws IOException {
        List<ByteString> ret = Lists.newArrayList();

        for (File dir : basedir.listFiles()) {
            if (!dir.isDirectory()) {
                continue;
            }

            String name = dir.getName();
            if (name.charAt(0) == '_') {
                continue;
            }

            if (prefix.length() > name.length()) {
                if (!prefix.startsWith(name)) {
                    continue;
                }
            } else {
                if (!name.startsWith(prefix)) {
                    continue;
                }
            }

            listWithPrefix(ret, dir, prefix);
        }

        return ret;
    }

    private void listWithPrefix(List<ByteString> ret, File dir, String prefix) {
        for (File file : dir.listFiles()) {
            if (!file.isFile()) {
                continue;
            }

            String name = file.getName();
            if (!name.startsWith(prefix)) {
                continue;
            }

            try {
                byte[] bytes = Hex.fromHex(name);
                ret.add(ByteString.copyFrom(bytes));
            } catch (IllegalArgumentException e) {
                log.warn("Unable to parse filename: " + name, e);
                continue;
            }
        }
    }

}
TOP

Related Classes of io.fathom.cloud.blobs.LocalFilesystemBlobStore

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.