/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved.
*
* 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.hazelcast.impl;
import com.hazelcast.core.Member;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.Data;
import com.hazelcast.partition.MigrationEvent;
import com.hazelcast.partition.MigrationListener;
import com.hazelcast.partition.Partition;
import com.hazelcast.partition.PartitionService;
import com.hazelcast.util.ResponseQueueFactory;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.*;
import java.util.logging.Level;
import static com.hazelcast.nio.IOUtil.toData;
public class PartitionServiceImpl implements PartitionService {
private final ILogger logger;
private final ConcurrentMap<Integer, PartitionProxy> mapPartitions = new ConcurrentHashMap<Integer, PartitionProxy>();
private final List<MigrationListener> lsMigrationListeners = new CopyOnWriteArrayList<MigrationListener>();
private final ConcurrentMapManager concurrentMapManager;
private final Set<Partition> partitions;
public PartitionServiceImpl(ConcurrentMapManager concurrentMapManager) {
this.logger = concurrentMapManager.node.getLogger(PartitionService.class.getName());
this.concurrentMapManager = concurrentMapManager;
this.partitions = new TreeSet<Partition>();
for (int i = 0; i < concurrentMapManager.PARTITION_COUNT; i++) {
PartitionProxy partitionProxy = new PartitionProxy(i);
partitions.add(partitionProxy);
mapPartitions.put(i, partitionProxy);
}
}
public int getOwnedPartitionCount() {
int currentCount = 0;
for (Partition partition : partitions) {
if (partition.getOwner() == null || partition.getOwner().localMember()) {
currentCount++;
}
}
return currentCount;
}
public Set<Partition> getPartitions() {
return partitions;
}
public PartitionProxy getPartition(Object key) {
final Data keyData = toData(key);
final int partitionId = concurrentMapManager.getPartitionId(keyData);
return getPartition(partitionId);
}
public PartitionProxy getPartition(int partitionId) {
return mapPartitions.get(partitionId);
}
void doFireMigrationEvent(final boolean started, final MigrationEvent migrationEvent) {
if (migrationEvent == null) throw new IllegalArgumentException("MigrationEvent is null.");
if (!started) {
concurrentMapManager.node.executorManager.executeNow(new Runnable() {
public void run() {
if (migrationEvent.getOldOwner() != null && migrationEvent.getOldOwner().localMember()) {
for (CMap cMap : concurrentMapManager.maps.values()) {
for (Record record : cMap.getMapIndexService().getOwnedRecords()) {
if (record.getBlockId() == migrationEvent.getPartitionId()) {
cMap.getMapIndexService().remove(record);
}
}
}
}
}
});
}
for (final MigrationListener migrationListener : lsMigrationListeners) {
concurrentMapManager.node.executorManager.executeNow(new Runnable() {
public void run() {
if (started) {
migrationListener.migrationStarted(migrationEvent);
} else {
migrationListener.migrationCompleted(migrationEvent);
}
}
});
}
}
public void addMigrationListener(MigrationListener migrationListener) {
lsMigrationListeners.add(migrationListener);
}
public void removeMigrationListener(MigrationListener migrationListener) {
lsMigrationListeners.remove(migrationListener);
}
public void reset() {
}
boolean allPartitionsOwned() {
Set<Partition> partitions = getPartitions();
for (Partition partition : partitions) {
if (partition.getOwner() == null) {
return false;
}
}
return true;
}
private MemberImpl getPartitionOwner(final int partitionId) throws InterruptedException {
final BlockingQueue<MemberImpl> responseQ = ResponseQueueFactory.newResponseQueue();
concurrentMapManager.enqueueAndReturn(new Processable() {
public void process() {
MemberImpl memberOwner = null;
try {
Address ownerAddress = concurrentMapManager.getPartitionManager().getOwner(partitionId);
if (ownerAddress != null) {
if (concurrentMapManager.thisAddress.equals(ownerAddress)) {
memberOwner = concurrentMapManager.thisMember;
} else {
memberOwner = concurrentMapManager.getMember(ownerAddress);
}
}
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
} finally {
responseQ.offer(memberOwner);
}
}
});
return responseQ.poll(10, TimeUnit.SECONDS);
}
class PartitionProxy implements Partition, Comparable {
final int partitionId;
PartitionProxy(int partitionId) {
this.partitionId = partitionId;
}
public int getPartitionId() {
return partitionId;
}
public Member getOwner() {
Address address = concurrentMapManager.getPartitionManager().getPartition(partitionId).getOwner();
if (address != null) {
Member member = concurrentMapManager.node.getClusterImpl().getMember(address);
if (member != null) {
return member;
}
}
try {
return getPartitionOwner(partitionId);
} catch (InterruptedException e) {
return null;
}
}
public int compareTo(Object o) {
PartitionProxy partition = (PartitionProxy) o;
Integer id = partitionId;
return (id.compareTo(partition.getPartitionId()));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PartitionProxy partition = (PartitionProxy) o;
return partitionId == partition.partitionId;
}
@Override
public int hashCode() {
return partitionId;
}
@Override
public String toString() {
return "Partition [" +
+partitionId +
"], owner=" + getOwner();
}
}
}