Package com.netflix.priam.backup

Source Code of com.netflix.priam.backup.IncrementalRestore

/**
* Copyright 2013 Netflix, 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 com.netflix.priam.backup;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.cassandra.io.sstable.SSTableLoaderWrapper;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.streaming.PendingFile;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.netflix.priam.IConfiguration;
import com.netflix.priam.PriamServer;
import com.netflix.priam.backup.AbstractBackupPath.BackupFileType;
import com.netflix.priam.backup.IMessageObserver.RESTORE_MESSAGE_STATUS;
import com.netflix.priam.backup.IMessageObserver.RESTORE_MESSAGE_TYPE;
import com.netflix.priam.scheduler.SimpleTimer;
import com.netflix.priam.scheduler.TaskTimer;
import com.netflix.priam.utils.Sleeper;


/*
* Incremental SSTable Restore using SSTable Loader
*/
@Singleton
public class IncrementalRestore extends AbstractRestore
{
    private static final Logger logger = LoggerFactory.getLogger(IncrementalRestore.class);
    public static final String JOBNAME = "INCR_RESTORE_THREAD";
    private static final String SYSTEM_KEYSPACE = "system";
    private final List<String> streamedIncrementalRestorePaths = new ArrayList<String>();
    static List<IMessageObserver> observers = new ArrayList<IMessageObserver>();

    /* Marked public for testing */
    public static final Pattern SECONDRY_INDEX_PATTERN = Pattern.compile("^[a-zA-Z_0-9-]+\\.[a-zA-Z_0-9-]+\\.[a-z1-9]{2,4}$");

    private final File restoreDir;
   
    @Inject
    private SSTableLoaderWrapper loader;
   
    @Inject
    private PriamServer priamServer;
   
    @Inject
    public IncrementalRestore(IConfiguration config, @Named("incr_restore")IBackupFileSystem fs, Sleeper sleeper)
    {
        super(config, fs,JOBNAME, sleeper);
        this.restoreDir = new File(config.getDataFileLocation(), "restore_incremental");
    }

    @Override
    public void execute() throws Exception
    {
        String prefix = config.getRestorePrefix();
        if (Strings.isNullOrEmpty(prefix))
        {
            logger.error("Restore prefix is not set, skipping incremental restore to avoid looping over the incremental backups. Plz check the configurations");
            return; // No point in restoring the files which was just backedup.
        }

        if (config.isRestoreClosestToken())
        {
            priamServer.getId().getInstance().setToken(restoreToken.toString());
        }

        Date start = tracker.first().time;
        Iterator<AbstractBackupPath> incrementals = fs.list(prefix, start, Calendar.getInstance().getTime());
        FileUtils.createDirectory(restoreDir); // create restore dir.
        while (incrementals.hasNext())
        {
            AbstractBackupPath temp = incrementals.next();
            if (tracker.contains(temp) || start.compareTo(temp.time) >= 0)
                continue; // ignore the ones which where already downloaded.
            if (temp.getType() != BackupFileType.SST)
                continue; // download SST's only.
            // skip System Keyspace, else you will run into concurrent schema issues.
            if (temp.getKeyspace().equalsIgnoreCase("System"))
                continue;
            /* Cassandra will rebuild Secondary index's after streaming is complete so we can ignore those */
            if (SECONDRY_INDEX_PATTERN.matcher(temp.fileName).matches()) // Make this use the constant from 1.1
                continue;
           
            // Create Directory for Individual Token respective to each incoming file
            File tokenDir = new File(restoreDir, temp.getToken());
            FileUtils.createDirectory(tokenDir);
            File keyspaceDir = config.getTargetKSName() == null ? new File(tokenDir, temp.keyspace) : new File(tokenDir, config.getTargetKSName());
            FileUtils.createDirectory(keyspaceDir);
            File columnFamilyDir = config.getTargetCFName() == null ? new File(keyspaceDir, temp.columnFamily) : new File(tokenDir, config.getTargetCFName());
            FileUtils.createDirectory(columnFamilyDir);
            logger.debug("*** Keyspace = "+keyspaceDir.getAbsolutePath()+ " Column Family = "+columnFamilyDir.getAbsolutePath()+" File = "+temp.getRemotePath());
            if(config.getTargetKSName() != null || config.getTargetCFName() != null)
                 temp.fileName = renameIncrementalRestoreFile(temp.fileName);
            download(temp, new File(columnFamilyDir, temp.fileName));
        }
        // wait for all the downloads in this batch to complete.
        waitToComplete();
        // stream the SST's in the dir
        for (File tokenDir : restoreDir.listFiles())
        {
            for (File keyspaceDir : tokenDir.listFiles())
            {
                for(File columnFamilyDir : keyspaceDir.listFiles())
                {
                  Collection<PendingFile> streamedSSTs = loader.stream(columnFamilyDir);
                  addToStreamedIncrementalRestorePaths(streamedSSTs);
                  if(streamedIncrementalRestorePaths.size() > 0)
                  {
                    logger.debug("streamedIncrementalRestorePaths > 0, hence notifying observers");
                    notifyStreamedDataObservers();
                  }
                  // cleanup the dir which where streamed.
                  loader.deleteCompleted(streamedSSTs);
                }
            }
        }
    }

    /**
     * Run every 20 Sec
     */
    public static TaskTimer getTimer()
    {
        return new SimpleTimer(JOBNAME, 20L * 1000);
    }

    @Override
    public String getName()
    {
        return JOBNAME;
    }
   
    public static void addObserver(IMessageObserver observer)
    {
        observers.add(observer);
    }
   
    public static void removeObserver(IMessageObserver observer)
    {
        observers.remove(observer);
    }
   
    public void addToStreamedIncrementalRestorePaths(Collection<PendingFile> streamedSSTs)
    {
        streamedIncrementalRestorePaths.clear();
        for(PendingFile streamedSST:streamedSSTs)
          streamedIncrementalRestorePaths.add(streamedSST.getFilename());
    }
   
    public void notifyStreamedDataObservers()
    {
        for(IMessageObserver observer : observers)
        {
            if(observer != null)
            {
              observer.update(RESTORE_MESSAGE_TYPE.INCREMENTAL,streamedIncrementalRestorePaths,RESTORE_MESSAGE_STATUS.STREAMED);
            }
            else
              logger.error("Streamed Observer is Null, hence can not notify ...");
        }
    }
   
    public String renameIncrementalRestoreFile(String fileToBeRenamed)
    {
    String[] splitToBeRenamed = StringUtils.split(fileToBeRenamed, '-');
   
    // Rename KS
    if (config.getTargetKSName() != null)
    {
      logger.info("Old Keyspace = ["+splitToBeRenamed[0]+"] --> New Keyspace = ["+config.getTargetKSName()+"]");
      splitToBeRenamed[0] = config.getTargetKSName();
    }
   
    // Rename CF
    if(config.getTargetCFName() != null)
    {
      logger.info("Old Column Family = ["+splitToBeRenamed[1]+"] --> New Column Family = ["+config.getTargetCFName()+"]");
      splitToBeRenamed[1] = config.getTargetCFName();
    }
   
    logger.info("Orig Filename = ["+fileToBeRenamed+"] --> New Filename = ["+StringUtils.join(splitToBeRenamed,'-')+"]");

    return StringUtils.join(splitToBeRenamed,'-');

    }

}
TOP

Related Classes of com.netflix.priam.backup.IncrementalRestore

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.