Package com.rackspacecloud.blueflood.CloudFilesBackfiller.download

Source Code of com.rackspacecloud.blueflood.CloudFilesBackfiller.download.CloudFilesManager

/*
* Copyright 2014 Rackspace
*
*    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.

* Original author: gdusbabek
* Modified by: chinmay
*/

package com.rackspacecloud.blueflood.CloudFilesBackfiller.download;

import com.codahale.metrics.Timer;
import com.rackspacecloud.blueflood.CloudFilesBackfiller.service.BackFillerConfig;
import com.rackspacecloud.blueflood.rollup.Granularity;
import com.rackspacecloud.blueflood.service.Configuration;
import com.rackspacecloud.blueflood.types.Range;
import com.rackspacecloud.blueflood.utils.Metrics;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.io.Payload;
import org.jclouds.location.reference.LocationConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CloudFilesManager implements FileManager {

    private static final Logger log = LoggerFactory.getLogger(CloudFilesManager.class);
    private static final int BUF_SIZE = 0x00100000; // 1MB.
    private static final String lastMarkerPath = ".last_marker"; // Marker really important for this tool. Manually start hacking till we start seeing files
    private final String user;
    private final String key;
    private final String provider; // = "cloudfiles-us";
    private final String zone; // = "IAD";
    private final String container; // = "metric-data-archive";
    private final int batchSize;
    private final List<NewFileListener> listeners = new ArrayList<NewFileListener>();
   
    private String lastMarker = MarkerUtils.readLastMarker();
    private ExecutorService downloadWorkers = Executors.newFixedThreadPool(5);

    public static final long START_TIME = Configuration.getInstance().getLongProperty(BackFillerConfig.REPLAY_PERIOD_START);
    public static final long STOP_TIME = Configuration.getInstance().getLongProperty(BackFillerConfig.REPLAY_PERIOD_STOP);;

    public static final Iterable<Range> ranges = Range.rangesForInterval(Granularity.MIN_5, START_TIME, STOP_TIME);

    private static Timer downloadTimer = Metrics.timer(CloudFilesManager.class, "Cloud Files Download Timer");
   
    public CloudFilesManager(String user, String key, String provider, String zone, String container, int batchSize) {
        this.user = user;
        this.key = key;
        this.provider = provider;
        this.zone = zone;
        this.container = container;
        this.batchSize = batchSize;
    }

    public synchronized boolean hasNewFiles() {
        // see if there are any files since lastMarker.
        BlobStoreContext ctx = ContextBuilder.newBuilder(provider)
                .credentials(user, key)
                .overrides(new Properties() {{
                    setProperty(LocationConstants.PROPERTY_ZONE, zone);
                }})
                .buildView(BlobStoreContext.class);
       
        BlobStore store = ctx.getBlobStore();
        ListContainerOptions options = new ListContainerOptions().maxResults(batchSize).afterMarker(lastMarker);
        PageSet<? extends StorageMetadata> pages = store.list(container, options);
       
        log.debug("Saw {} new files since {}", pages.size() == batchSize ? "many" : Integer.toString(pages.size()), lastMarker);
        boolean emptiness = getBlobsWithinRange(pages).isEmpty();

        if(emptiness) {
            log.warn("No file found within range {}", new Range(START_TIME, STOP_TIME));
        } else {
            log.debug("New files found within range {}", new Range(START_TIME, STOP_TIME));
        }

        return !emptiness;
    }

    private NavigableMap<Long,String> getBlobsWithinRange(PageSet<? extends StorageMetadata> pages) {
        // TreeMap used because of sorted property
        TreeMap<Long, String> tsToBlobName = new TreeMap<Long, String>();
        for (StorageMetadata blobMeta : pages) {
            String fileName = blobMeta.getName(); // 20140226_1393442533000.json.gz
            String dateAndTs = fileName.split("\\.", 2)[0].trim(); // 20140226_1393442533000
            String tsCreated = dateAndTs.split("_")[1].trim(); // 1393442533000
            long ts = Long.parseLong(tsCreated);
            tsToBlobName.put(ts, fileName);
        }
        //Gets key within the time range specified
        NavigableMap<Long, String> mapWithinRange = tsToBlobName.subMap(START_TIME - 60000*15, true, STOP_TIME + 60000*30, true);
        if(mapWithinRange.isEmpty()) {
            lastMarker = tsToBlobName.lastEntry().getValue().trim();
            synchronized (CloudFilesManager.this) {
                // this is where we resume from.
                MarkerUtils.writeLastMarker(tsToBlobName.lastEntry().getValue().trim());
            }
        }
        return mapWithinRange;
    }
   
    private class BlobDownload implements Callable<String> {
       
        private final File downloadDir;
        private final String container;
        private final String name;
        private final BlobStore store;
       
        public BlobDownload(File downloadDir, BlobStore store, String container, String name) {
            this.downloadDir = downloadDir;
            this.store = store;
            this.container = container;
            this.name = name;
        }
       
        public String call() throws Exception {
            Blob blob = store.getBlob(container, name);
            Payload payload = blob.getPayload();
            InputStream is = payload.getInput();
            File tempFile = new File(downloadDir, name + ".tmp");
            Timer.Context downloadContext = downloadTimer.time();
            try {
                long read = 0;
                long length = payload.getContentMetadata().getContentLength();
                OutputStream out = new FileOutputStream(tempFile, false);
                byte[] buf = new byte[BUF_SIZE];
                while (read < length) {
                    int avail = Math.min(is.available(), BUF_SIZE);
                    if (avail < 0) {
                        try { Thread.sleep(100); } catch (Exception ex) {}
                    } else {
                        int readLength = is.read(buf);
                        read += readLength;
                        out.write(buf, 0, readLength);
                    }
                }
                out.flush();
                out.close();
                File permFile = new File(downloadDir, name);
                if (tempFile.renameTo(permFile)) {
                    notifyListeners(permFile);
                } else {
                    throw new IOException("Could not rename file");
                }
            } catch (IOException ex) {
                tempFile.delete();
            } finally {
                payload.release();
                downloadContext.stop();
            }
            return name;
        }
    }
   
    public synchronized void downloadNewFiles(File downloadDir) {
        log.info("Downloading new files since {}", lastMarker);
       
        BlobStoreContext ctx = ContextBuilder.newBuilder(provider)
                .credentials(user, key)
                .overrides(new Properties() {{
                    setProperty(LocationConstants.PROPERTY_ZONE, zone);
                }})
                .buildView(BlobStoreContext.class);

        // threadsafe according to https://jclouds.apache.org/documentation/userguide/blobstore-guide/
        BlobStore store = ctx.getBlobStore();
        ListContainerOptions options = new ListContainerOptions().maxResults(batchSize).afterMarker(lastMarker);
        PageSet<? extends StorageMetadata> pages = store.list(container, options);

        //Gets key within the time range specified
        NavigableMap<Long, String> mapWithinRange = getBlobsWithinRange(pages);

        //Download only for keys within that range
        for(Map.Entry<Long, String> blobMeta : mapWithinRange.entrySet()) {
            log.info("Downloading file: " + blobMeta.getValue());
            downloadWorkers.submit(new BlobDownload(downloadDir, store, container, blobMeta.getValue()));
            lastMarker = blobMeta.getValue();
            synchronized (CloudFilesManager.this) {
                // this is where we resume from.
                MarkerUtils.writeLastMarker(blobMeta.getValue());
            }
        }
        log.info("Updated the last marker value as " + lastMarker);
    }

    public void addNewFileListener(NewFileListener listener) {
        if (!listeners.contains(listener))
            listeners.add(listener);
    }
   
    private void notifyListeners(File newFile) {
        for (NewFileListener listener : listeners) {
            try {
                listener.fileReceived(newFile);
            } catch (Throwable allSortsOfBadness) {
                log.error(allSortsOfBadness.getMessage(), allSortsOfBadness);
            }
        }
    }
   
    private static class MarkerUtils {
        private static final Lock lock = new ReentrantLock();
       
        public static String readLastMarker() {
            lock.lock();
            try {
                File f = new File(lastMarkerPath);
                if (!f.exists())
                    return "";
                else {
                    try {
                        byte[] buf = new byte[(int)f.length()];
                        InputStream in = new FileInputStream(f);
                        int read = 0;
                        while (read < buf.length)
                            read += in.read(buf, read, buf.length - read);
                        in.close();
                        return new String(buf).trim();
                    } catch (Throwable th) {
                        log.error(th.getMessage(), th);
                        return "";
                    }
                }
            } finally {
                lock.unlock();
            }
        }
       
        public static void writeLastMarker(String s) {
            lock.lock();
            try {
                OutputStream out = new FileOutputStream(new File(lastMarkerPath));
                out.write(s.getBytes());
                out.close();
            } catch (Throwable th) {
                log.error(th.getMessage(), th);
            } finally {
                lock.unlock();
            }
        }
    }
}
TOP

Related Classes of com.rackspacecloud.blueflood.CloudFilesBackfiller.download.CloudFilesManager

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.