/*
* 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.partition;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.impl.FactoryImpl;
import com.hazelcast.impl.Node;
import com.hazelcast.impl.PartitionManager;
import com.hazelcast.impl.Record;
import com.hazelcast.impl.base.DataRecordEntry;
import com.hazelcast.impl.base.RecordSet;
import com.hazelcast.impl.concurrentmap.CostAwareRecordList;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.DataSerializable;
import com.hazelcast.nio.IOUtil;
import java.io.*;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
public class MigrationTask implements Callable<Boolean>, DataSerializable, HazelcastInstanceAware {
private int partitionId;
private int replicaIndex;
private byte[] bytesRecordSet;
private Address from;
private int recordCount;
private transient HazelcastInstance hazelcast;
public MigrationTask() {
}
public MigrationTask(int partitionId, CostAwareRecordList costAwareRecordList,
int replicaIndex, Address from) throws IOException {
this.partitionId = partitionId;
this.replicaIndex = replicaIndex;
this.from = from;
this.recordCount = costAwareRecordList.getRecords().size();
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) (costAwareRecordList.getCost() / 100));
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new DeflaterOutputStream(bos));
List<Record> lsRecordsToMigrate = costAwareRecordList.getRecords();
dos.writeInt(lsRecordsToMigrate.size());
for (Record record : lsRecordsToMigrate) {
new DataRecordEntry(record, true).writeData(dos);
}
} finally {
IOUtil.closeResource(dos);
}
bytesRecordSet = bos.toByteArray();
}
public Boolean call() throws Exception {
Node node = ((FactoryImpl) hazelcast).node;
PartitionManager pm = node.concurrentMapManager.getPartitionManager();
DataInputStream dis = null;
try {
ByteArrayInputStream bais = new ByteArrayInputStream(bytesRecordSet);
dis = new DataInputStream(new InflaterInputStream(bais));
int size = dis.readInt();
RecordSet recordSet = new RecordSet();
for (int i = 0; i < size; i++) {
DataRecordEntry r = new DataRecordEntry();
r.readData(dis);
recordSet.addDataRecordEntry(r);
}
if (recordCount != recordSet.getRecords().size()) {
getLogger().log(Level.SEVERE, "Migration record count mismatch! => " +
"expected-count: " + size + ", actual-count: " + recordSet.getRecords().size() +
"\nfrom: " + from + ", partition: " + partitionId + ", replica: " + replicaIndex);
}
pm.doMigrate(partitionId, replicaIndex, recordSet, from);
return Boolean.TRUE;
} catch (Throwable e) {
Level level = Level.WARNING;
if (e instanceof IllegalStateException) {
level = Level.FINEST;
}
getLogger().log(level, e.getMessage(), e);
} finally {
IOUtil.closeResource(dis);
}
return Boolean.FALSE;
}
private ILogger getLogger() {
return ((FactoryImpl) hazelcast).node.getLogger(MigrationTask.class.getName());
}
public void writeData(DataOutput out) throws IOException {
try {
out.writeInt(partitionId);
out.writeInt(replicaIndex);
out.writeInt(recordCount);
from.writeData(out);
out.writeInt(bytesRecordSet.length);
out.write(bytesRecordSet);
} catch (Throwable e) {
e.printStackTrace();
}
}
public void readData(DataInput in) throws IOException {
partitionId = in.readInt();
replicaIndex = in.readInt();
recordCount = in.readInt();
from = new Address();
from.readData(in);
int size = in.readInt();
bytesRecordSet = new byte[size];
in.readFully(bytesRecordSet);
}
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcast = hazelcastInstance;
}
}