Package org.apache.cassandra.db

Source Code of org.apache.cassandra.db.HintedHandOffManager

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.cassandra.db;

import java.util.Collection;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;

import org.apache.cassandra.concurrent.DebuggableScheduledThreadPoolExecutor;
import org.apache.cassandra.concurrent.ThreadFactoryImpl;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.gms.FailureDetector;
import org.apache.cassandra.net.EndPoint;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.IComponentShutdown;
import org.apache.cassandra.service.StorageService;


/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/

public class HintedHandOffManager implements IComponentShutdown
{
    private static HintedHandOffManager instance_;
    private static Lock lock_ = new ReentrantLock();
    private static Logger logger_ = Logger.getLogger(HintedHandOffManager.class);
    public static final String key_ = "HintedHandOffKey";
    final static long intervalInMins_ = 20;
    private ScheduledExecutorService executor_ = new DebuggableScheduledThreadPoolExecutor(1, new ThreadFactoryImpl("HINTED-HANDOFF-POOL"));


    public static HintedHandOffManager instance()
    {
        if ( instance_ == null )
        {
            lock_.lock();
            try
            {
                if ( instance_ == null )
                    instance_ = new HintedHandOffManager();
            }
            finally
            {
                lock_.unlock();
            }
        }
        return instance_;
    }

    class HintedHandOff implements Runnable
    {
        private ColumnFamilyStore columnFamilyStore_ = null;
        private EndPoint endPoint_ = null;

        HintedHandOff(ColumnFamilyStore columnFamilyStore)
        {
          columnFamilyStore_ = columnFamilyStore;
        }
        HintedHandOff(EndPoint endPoint)
        {
          endPoint_ = endPoint;
        }

        private boolean sendMessage(String endpointAddress, String key) throws Exception
        {
          boolean success = false; // TODO : fix the hack we need to make sure the data is written on the other end.
          if(FailureDetector.instance().isAlive(new EndPoint(endpointAddress, DatabaseDescriptor.getControlPort())))
          {
            success = true;
          }
          else
          {
            return success;
          }
          Table table = Table.open(DatabaseDescriptor.getTables().get(0));
          Row row = null;
          row = table.get(key);
          RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), row);
      RowMutationMessage rmMsg = new RowMutationMessage(rm);
      Message message = RowMutationMessage.makeRowMutationMessage( rmMsg );
      EndPoint endPoint = new EndPoint(endpointAddress, DatabaseDescriptor.getStoragePort());
      MessagingService.getMessagingInstance().sendOneWay(message, endPoint);
      return success;
        }

        private void deleteEndPoint(String endpointAddress, String key) throws Exception
        {
          RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), key_);
          rm.delete(Table.hints_ + ":" + key + ":" + endpointAddress, System.currentTimeMillis());
          rm.apply();
        }

        private void deleteKey(String key) throws Exception
        {
          RowMutation rm = new RowMutation(DatabaseDescriptor.getTables().get(0), key_);
          rm.delete(Table.hints_ + ":" + key, System.currentTimeMillis());
          rm.apply();
        }

        private void runHints()
        {
            logger_.debug("Started  hinted handoff " + columnFamilyStore_.columnFamily_);

            // 1. Scan through all the keys that we need to handoff
            // 2. For each key read the list of recepients and send
            // 3. Delete that recepient from the key if write was successful
            // 4. If all writes were success for a given key we can even delete the key .
            // 5. Now force a flush
            // 6. Do major compaction to clean up all deletes etc.
            // 7. I guess we r done
            Table table =  Table.open(DatabaseDescriptor.getTables().get(0));
            ColumnFamily hintedColumnFamily = null;
            boolean success = false;
            boolean allsuccess = true;
            try
            {
              hintedColumnFamily = table.get(key_, Table.hints_);
              if(hintedColumnFamily == null)
              {
                    // Force flush now
                    columnFamilyStore_.forceFlush();
                return;
              }
              Collection<IColumn> keys = hintedColumnFamily.getAllColumns();
              if(keys != null)
              {
                  for(IColumn key : keys)
                  {
                    // Get all the endpoints for teh key
                    Collection<IColumn> endpoints =  key.getSubColumns();
                    allsuccess = true;
                    if ( endpoints != null )
                    {
                      for(IColumn endpoint : endpoints )
                      {
                        success = sendMessage(endpoint.name(), key.name());
                        if(success)
                        {
                          // Delete the endpoint from the list
                          deleteEndPoint(endpoint.name(), key.name());
                        }
                        else
                        {
                          allsuccess = false;
                        }
                      }
                    }
                    if(endpoints == null || allsuccess)
                    {
                      // Delete the key itself.
                      deleteKey(key.name());
                    }
                  }
              }
                // Force flush now
                columnFamilyStore_.forceFlush();

                // Now do a major compaction
                columnFamilyStore_.forceCompaction(null, null, 0, null);
            }
            catch ( Exception ex)
            {
              logger_.warn(ex.getMessage());
            }
            logger_.debug("Finished hinted handoff ..."+columnFamilyStore_.columnFamily_);
        }

        private void runDeliverHints(EndPoint to)
        {
            logger_.debug("Started  hinted handoff for endPoint " + endPoint_.getHost());

            // 1. Scan through all the keys that we need to handoff
            // 2. For each key read the list of recepients if teh endpoint matches send
            // 3. Delete that recepient from the key if write was successful

            Table table =  Table.open(DatabaseDescriptor.getTables().get(0));
            ColumnFamily hintedColumnFamily = null;
            boolean success = false;
            try
            {
              hintedColumnFamily = table.get(key_, Table.hints_);
              if(hintedColumnFamily == null)
                return;
              Collection<IColumn> keys = hintedColumnFamily.getAllColumns();
              if(keys != null)
              {
                  for(IColumn key : keys)
                  {
                    // Get all the endpoints for teh key
                    Collection<IColumn> endpoints =  key.getSubColumns();
                    if ( endpoints != null )
                    {
                      for(IColumn endpoint : endpoints )
                      {
                        if(endpoint.name().equals(endPoint_.getHost()))
                        {
                          success = sendMessage(endpoint.name(), key.name());
                          if(success)
                          {
                            // Delete the endpoint from the list
                            deleteEndPoint(endpoint.name(), key.name());
                          }
                        }
                      }
                    }
                    if(endpoints == null)
                    {
                      // Delete the key itself.
                      deleteKey(key.name());
                    }
                  }
              }
            }
            catch ( Exception ex)
            {
              logger_.warn(ex.getMessage());
            }
            logger_.debug("Finished hinted handoff for endpoint ..." + endPoint_.getHost());
        }

        public void run()
        {
          if(endPoint_ == null)
          {
            runHints();
          }
          else
          {
            runDeliverHints(endPoint_);
          }

        }
    }

    public HintedHandOffManager()
    {
      StorageService.instance().registerComponentForShutdown(this);
    }

    public void submit(ColumnFamilyStore columnFamilyStore)
    {
      executor_.scheduleWithFixedDelay(new HintedHandOff(columnFamilyStore), HintedHandOffManager.intervalInMins_,
          HintedHandOffManager.intervalInMins_, TimeUnit.MINUTES);
    }

    /*
     * This method is used to deliver hints to a particular endpoint.
     * When we learn that some endpoint is back up we deliver the data
     * to him via an event driven mechanism.
    */
    public void deliverHints(EndPoint to)
    {
      executor_.submit(new HintedHandOff(to));
    }

    public void shutdown()
    {
      executor_.shutdownNow();
    }
}
TOP

Related Classes of org.apache.cassandra.db.HintedHandOffManager

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.