All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rackspacecloud.blueflood.service.LocatorFetchRunnable Maven / Gradle / Ivy

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

package com.rackspacecloud.blueflood.service;

import com.netflix.astyanax.model.ColumnFamily;
import com.rackspacecloud.blueflood.io.AstyanaxIO;
import com.rackspacecloud.blueflood.io.AstyanaxReader;
import com.rackspacecloud.blueflood.rollup.Granularity;
import com.rackspacecloud.blueflood.types.Locator;
import com.rackspacecloud.blueflood.types.Range;
import com.netflix.astyanax.model.Column;
import com.rackspacecloud.blueflood.types.Rollup;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Timer;
import com.yammer.metrics.core.TimerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * fetches locators for a given slot and feeds a worker queue with rollup work. When those are all done notifies the
 * RollupService that slot can be removed from running.
  */
class LocatorFetchRunnable implements Runnable {
    private static final Logger log = LoggerFactory.getLogger(LocatorFetchRunnable.class);
    private static final int LOCATOR_WAIT_FOR_ALL_SECS = 1000;
    
    private final ThreadPoolExecutor rollupExecutor;
    private final String parentSlotKey;
    private final ScheduleContext scheduleCtx;
    private final long serverTime;
    private static final Timer rollupLocatorExecuteTimer = Metrics.newTimer(RollupService.class, "Locate and Schedule Rollups for Slot", TimeUnit.MILLISECONDS, TimeUnit.SECONDS);


    LocatorFetchRunnable(ScheduleContext scheduleCtx, String destSlotKey, ThreadPoolExecutor rollupExecutor) {
        this.rollupExecutor = rollupExecutor;
        this.parentSlotKey = destSlotKey;
        this.scheduleCtx = scheduleCtx;
        this.serverTime = scheduleCtx.getCurrentTimeMillis();
    }
    
    public void run() {
        final TimerContext timerCtx = rollupLocatorExecuteTimer.time();
        final Granularity gran = Granularity.granularityFromKey(parentSlotKey);
        final int parentSlot = Granularity.slotFromKey(parentSlotKey);
        final int shard = Granularity.shardFromKey(parentSlotKey);
        final Range parentRange = gran.deriveRange(parentSlot, serverTime);
        Granularity finerGran;

        try {
            finerGran = gran.finer();
        } catch (Exception ex) {
            log.error("No finer granularity available than " + gran);
            return;
        }

        if (log.isTraceEnabled())
            log.trace("Getting locators for {} {} @ {}", new Object[]{parentSlotKey, parentRange.toString(), scheduleCtx.getCurrentTimeMillis()});
        // todo: I can see this set becoming a memory hog.  There might be a better way of doing this.
        boolean success = true;
        long waitStart = System.currentTimeMillis();
        int rollCount = 0;

        final RollupExecutionContext executionContext = new RollupExecutionContext(Thread.currentThread());
        for (Column locatorCol : AstyanaxReader.getInstance().getAllLocators(shard)) {
            final Locator locator = locatorCol.getName();
            final ColumnFamily srcCF = AstyanaxIO.getColumnFamilyMapper().get(finerGran.name());
            final ColumnFamily destCF = AstyanaxIO.getColumnFamilyMapper().get(gran.name());

            if (log.isTraceEnabled())
                log.trace("Rolling up (check,metric,dimension) {} for (gran,slot,shard) {}", locatorCol.getName(), parentSlotKey);
            try {
                executionContext.increment();
                final RollupContext rollupContext = new RollupContext(locator, parentRange, srcCF, destCF);
                rollupExecutor.execute(new RollupRunnable(executionContext, rollupContext));
                rollCount += 1;
            } catch (Throwable any) {
                // continue on, but log the problem so that we can fix things later.
                executionContext.decrement();
                log.error(any.getMessage(), any);
                log.error("Rollup failed for {} at {}", parentSlotKey, serverTime);
            }
        }
        
        if (success) {
            // now wait until ctx is drained. someone needs to be notified.
            log.debug("Waiting for rollups to finish for " + parentSlotKey);
            while (!executionContext.done()) {
                try { 
                    Thread.currentThread().sleep(LOCATOR_WAIT_FOR_ALL_SECS); 
                } catch (InterruptedException ex) {
                    if (log.isTraceEnabled())
                        log.trace("Woken wile waiting for rollups to coalesce for {} {}", parentSlotKey);
                } finally {
                    log.debug("Still waiting for rollups to finish for {} {}", parentSlotKey, System.currentTimeMillis() - waitStart);
                }
            }
            if (log.isDebugEnabled())
                log.debug("Finished {} rollups for (gran,slot,shard) {} in {}", new Object[] {rollCount, parentSlotKey, System.currentTimeMillis() - waitStart});
            this.scheduleCtx.clearFromRunning(parentSlotKey);
        } else {
            log.warn("Rollup execution of {} failed.", gran);
            this.scheduleCtx.pushBackToScheduled(parentSlotKey);
        }

        timerCtx.stop();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy