/* * Copyright 2014 Alexey Plotnik * * 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 org.stem.domain.topology; import com.google.common.collect.Lists; import java.util.*; public class DataMapping { public static final DataMapping EMPTY = new DataMapping(); private final Map<Long, Topology.ReplicaSet> map = new HashMap<>(); public DataMapping(Map<Long, Topology.ReplicaSet> map) { if (map == null) return; for (Map.Entry<Long, Topology.ReplicaSet> entry : map.entrySet()) { this.map.put(entry.getKey(), entry.getValue()); } } public DataMapping() { } public long size() { return map.size(); } public Map<Long, Topology.ReplicaSet> getMap() { return map; } public List<Long> getBuckets() { return Lists.newArrayList(map.keySet()); } public Topology.ReplicaSet getReplicas(Long bucket) { return map.get(bucket); } public boolean isEmpty() { return getMap().isEmpty(); } /** * Class that calculates how disk were moved between arbitrary data mappings * Thanks to developers of libcrunch (Twitter) * This class is a port of com.twitter.crunch.MappingDiff */ public static class Difference { public static Difference compute(DataMapping before, DataMapping after) { return new Difference(before, after); } Map<Long, List<Delta>> result = new HashMap<>(); protected Difference(DataMapping before, DataMapping after) { for (Long key : before.getBuckets()) { Topology.ReplicaSet l1 = before.getReplicas(key); Topology.ReplicaSet l2 = after.getReplicas(key); List<Delta> diff = calculateDiff(l1, l2); if (!diff.isEmpty()) result.put(key, diff); } List<Long> m2Keys = after.getBuckets(); m2Keys.removeAll(before.getBuckets()); for (Long key : m2Keys) { Topology.ReplicaSet list = after.getReplicas(key); if (!list.isEmpty()) result.put(key, wrapList(list, Move.ADDED)); } } private static List<Delta> calculateDiff(Topology.ReplicaSet before, Topology.ReplicaSet after) { if (null == before && null == after) return Collections.emptyList(); if (null == before) return wrapList(after, Move.ADDED); if (null == after) return wrapList(before, Move.REMOVED); List<Delta> result = new ArrayList<>(); for (Topology.Disk disk : before) { if (!after.contains(disk)) result.add(new Delta(disk, Move.REMOVED)); } for (Topology.Disk disk : after) { if (!before.contains(disk)) result.add(new Delta(disk, Move.ADDED)); } return result; } private static List<Delta> wrapList(Topology.ReplicaSet list, Move diff) { List<Delta> result = new ArrayList<>(); for (Topology.Disk disk : list) { result.add(new Delta(disk, diff)); } return result; } public static class Delta { public final Topology.Disk value; public final Move move; public Delta(Topology.Disk value, Move move) { this.value = value; this.move = move; } } public enum Move {ADDED, REMOVED} } }