Package net.tomp2p.synchronization

Source Code of net.tomp2p.synchronization.SyncBuilder

/*
* Copyright 2013 Thomas Bocek, Maxat Pernebayev
*
* 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 net.tomp2p.synchronization;

import io.netty.buffer.ByteBuf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;

import net.tomp2p.dht.DHTBuilder;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.FutureChannelCreator;
import net.tomp2p.futures.FutureDone;
import net.tomp2p.futures.FutureResponse;
import net.tomp2p.message.DataMap;
import net.tomp2p.message.Message;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.Number640;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.storage.AlternativeCompositeByteBuf;
import net.tomp2p.storage.Data;
import net.tomp2p.storage.DataBuffer;
import net.tomp2p.utils.Utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The builder for the synchronization. This class first sends an info message to get the checksums, then it checks what
* needs to be done, (nothing, full copy, diff).
*
* @author Thomas Bocek
* @author Maxat Pernebayev
*
*/
public class SyncBuilder extends DHTBuilder<SyncBuilder> {

    private static final Logger LOG = LoggerFactory.getLogger(SyncBuilder.class);
    private static final FutureDone<SyncStat> FUTURE_SHUTDOWN = new FutureDone<SyncStat>()
            .failed("sync builder - peer is shutting down");
    static final int DEFAULT_BLOCK_SIZE = 700;
   
    private final PeerAddress other;
    private final PeerSync peerSync;
    private final int blockSize;

    private DataMap dataMap;
    private Number640 key;
    private Set<Number640> keys;
    private NavigableMap<Number640, Collection<Number160>> dataMapHash;
    private ArrayList<Instruction> instructions;
    private boolean syncFromOldVersion = false;
   
    public SyncBuilder(final PeerSync peerSync, final PeerAddress other) {
      this(peerSync, other, DEFAULT_BLOCK_SIZE);
    }

    /**
     * Constructor.
     *
     * @param peer
     *            The responsible peer that performs synchronization
     */
    public SyncBuilder(final PeerSync peerSync, final PeerAddress other, final int blockSize) {
        super(peerSync.peerDHT(), Number160.ZERO);
        self(this);
        this.other = other;
        this.peerSync = peerSync;
        this.blockSize = blockSize;
    }

    public SyncBuilder dataMap(DataMap dataMap) {
        this.dataMap = dataMap;
        return this;
    }

    public Number640 key() {
        return key;
    }

    public SyncBuilder key(Number640 key) {
        this.key = key;
        return this;
    }

    public Set<Number640> keys() {
        return keys;
    }

    public SyncBuilder keys(Set<Number640> keys) {
        this.keys = keys;
        return this;
    }
   
    public SyncBuilder syncFromOldVersion() {
      syncFromOldVersion = true;
        return this;
    }
   
    public boolean isSyncFromOldVersion() {
        return syncFromOldVersion;
    }

    public SyncBuilder syncFromOldVersion(boolean syncFromOldVersion) {
        this.syncFromOldVersion = syncFromOldVersion;
        return this;
    }

    public DataMap dataMap() {
        if (dataMap != null) {
            return dataMap;
        } else {
            Map<Number640, Data> newDataMap = new HashMap<Number640, Data>();
            if (key != null) {
                Data data = peer.storageLayer().get(key);
                if (data == null) {
                    data = new Data().flag2();
                }
                newDataMap.put(key, data);
            }
            if (keys != null) {
                for (Number640 key : keys) {
                    Data data = peer.storageLayer().get(key);
                    if (data == null) {
                        data = new Data().flag2();
                    }
                    newDataMap.put(key, data);
                }
            }
            if (newDataMap.size() > 0) {
                return new DataMap(newDataMap);
            } else {
                throw new IllegalArgumentException("Need either dataMap, key, or keys!");
            }
        }
    }

    public NavigableMap<Number640, Collection<Number160>> dataMapHash() {
        if (dataMapHash == null) {
            dataMapHash = new TreeMap<Number640, Collection<Number160>>();
        }
        if (dataMap != null) {
          for (Map.Entry<Number640, Number160> entry : dataMap.convertToHash().entrySet()) {
            Set<Number160> hashSet = new HashSet<Number160>(1);
            hashSet.add(entry.getValue());
            dataMapHash.put(entry.getKey(), hashSet);
          }
        }
        if (key != null) {
          Set<Number160> hashSet = new HashSet<Number160>(1);
          hashSet.add(peer.storageLayer().get(key).hash());
            dataMapHash.put(key, hashSet);
        }
        if (keys != null) {
            for (Number640 key : keys) {
              Set<Number160> hashSet = new HashSet<Number160>(1);
              hashSet.add(peer.storageLayer().get(key).hash());
                dataMapHash.put(key, hashSet);
            }
        }
        return dataMapHash;
    }

    public ArrayList<Instruction> instructions() {
        return instructions;
    }

    public FutureDone<SyncStat> start() {
        if (peer.peer().isShutdown()) {
            return FUTURE_SHUTDOWN;
        }
        final FutureDone<SyncStat> futureSync = new FutureDone<SyncStat>();
        FutureChannelCreator futureChannelCreator = peer.peer().connectionBean().reservation().create(0, 2);
        Utils.addReleaseListener(futureChannelCreator, futureSync);
        futureChannelCreator.addListener(new BaseFutureAdapter<FutureChannelCreator>() {
            @Override
            public void operationComplete(final FutureChannelCreator future2) throws Exception {
                if (!future2.isSuccess()) {
                    futureSync.failed(future2);
                    LOG.error("checkDirect failed {}", future2.failedReason());
                    return;
                }
                final FutureResponse futureResponse = peerSync.syncRPC().infoMessage(other,
                        SyncBuilder.this, future2.channelCreator());
                futureResponse.addListener(new BaseFutureAdapter<FutureResponse>() {
                    @Override
                    public void operationComplete(FutureResponse future) throws Exception {
                        if (future.isFailed()) {
                            Utils.addReleaseListener(future2.channelCreator(), futureResponse);
                            futureSync.failed(future);
                            LOG.error("checkDirect failed {}", future.failedReason());
                            return;
                        }

                        Message responseMessage = future.responseMessage();
                        DataMap dataMap = responseMessage.dataMap(0);

                        if (dataMap == null) {
                          LOG.error("nothing received, something is wrong");
                            futureSync.failed("nothing received, something is wrong");
                            return;
                        }

                        Map<Number640, Data> retVal = new HashMap<Number640, Data>();
                        boolean syncMessageRequired = false;
                        int dataCopy = 0;
                        int dataOrig = 0;
                        //int dataCopyCount = 0;
                        //int diffCount = 0;
                        //int dataNotCopied = 0;
                        for (Map.Entry<Number640, Data> entry : dataMap.dataMap().entrySet()) {
                         
                          Data data = entry.getValue();
                          if(data.length() == 0) {
                            if(data.isFlag1()) {
                              LOG.debug("no sync required");
                              syncMessageRequired = false;
                            } else if(data.isFlag2()) {
                              LOG.debug("copy required for key {}",entry.getKey());
                              syncMessageRequired = true;
                              Data data2 = peer.storageLayer().get(entry.getKey());
                              dataOrig += data2.length();
                              //copy
                                    retVal.put(entry.getKey(), data2);
                                    dataCopy += data2.length();
                                   
                            }
                          } else {
                            LOG.debug("sync required");
                            syncMessageRequired = true;
                            Data data2 = peer.storageLayer().get(entry.getKey());
                            dataOrig += data2.length();
                            final ByteBuf buffer = data.buffer();
                            Number160 versionKey = SyncUtils.decodeHeader(buffer);
                            Number160 hash = SyncUtils.decodeHeader(buffer);
            
                            List<Checksum> checksums = SyncUtils.decodeChecksums(buffer);
                            // TODO: don't copy data, toBytes does a copy!
                            List<Instruction> instructions = RSync.instructions(
                                         data2.toBytes(), checksums, blockSize);
                           
                            AlternativeCompositeByteBuf abuf = AlternativeCompositeByteBuf.compBuffer();
                           
                            dataCopy += SyncUtils.encodeInstructions(instructions, versionKey, hash, abuf);
                            DataBuffer dataBuffer = new DataBuffer(abuf);
                            //diff
                            Data data1 = new Data(dataBuffer).flag1();
                                retVal.put(entry.getKey(), data1);                       
                          }
                        }
                        final SyncStat syncStat = new SyncStat(peer.peerAddress().peerId(), other.peerId(), dataCopy, dataOrig);
                        if (syncMessageRequired) {
                          SyncBuilder.this.dataMap(new DataMap(retVal));
                          FutureResponse fr = peerSync.syncRPC().syncMessage(other,
                                    SyncBuilder.this, future2.channelCreator());
                            fr.addListener(new BaseFutureAdapter<FutureResponse>() {
                                @Override
                                public void operationComplete(FutureResponse future) throws Exception {
                                    if (future.isFailed()) {
                                        futureSync.failed(future);
                                    } else {
                                        futureSync.done(syncStat);
                                    }
                                }
                            });
                        } else {
                          futureSync.done(syncStat);
                        }
                    }
                });
            }
        });
        return futureSync;
    }
}
TOP

Related Classes of net.tomp2p.synchronization.SyncBuilder

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.