/**
*
*/
package org.apache.cassandra.service;
/*
*
* 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.
*
*/
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.net.Message;
import org.apache.cassandra.locator.IEndPointSnitch;
import org.apache.cassandra.locator.DatacenterEndPointSnitch;
/**
* This class will block for the replication factor which is
* provided in the input map. it will block till we recive response from
* n nodes in each of our data centers.
*/
public class DatacenterSyncWriteResponseHandler extends WriteResponseHandler
{
private final Map<String, Integer> dcResponses = new HashMap<String, Integer>();
private final Map<String, Integer> responseCounts;
private final DatacenterEndPointSnitch endPointSnitch;
public DatacenterSyncWriteResponseHandler(Map<String, Integer> responseCounts, String table)
{
// Response is been managed by the map so make it 1 for the superclass.
super(1, table);
this.responseCounts = responseCounts;
endPointSnitch = (DatacenterEndPointSnitch) DatabaseDescriptor.getEndPointSnitch(table);
}
@Override
// synchronized for the benefit of dcResponses and responseCounts. "responses" itself
// is inherited from WRH and is concurrent.
// TODO can we use concurrent structures instead?
public synchronized void response(Message message)
{
try
{
String dataCenter = endPointSnitch.getLocation(message.getFrom());
Object blockFor = responseCounts.get(dataCenter);
// If this DC needs to be blocked then do the below.
if (blockFor != null)
{
Integer quorumCount = dcResponses.get(dataCenter);
if (quorumCount == null)
{
// Intialize and recognize the first response
dcResponses.put(dataCenter, 1);
}
else if ((Integer) blockFor > quorumCount)
{
// recognize the consequtive responses.
dcResponses.put(dataCenter, quorumCount + 1);
}
else
{
// No need to wait on it anymore so remove it.
responseCounts.remove(dataCenter);
}
}
}
catch (UnknownHostException e)
{
throw new RuntimeException(e);
}
responses.add(message);
// If done then the response count will be empty
if (responseCounts.isEmpty())
{
condition.signal();
}
}
}