/** * Tests A|6, A|7, A|8 and B|7, B|8, B|9 -> we should have a subviews in MergeView consisting of * only 2 elements: A|5 and B|5 */ public void testMultipleViewsBySameMembers() throws Exception { View a1 = View.create( a.getAddress(), 6, a.getAddress(), b.getAddress(), c.getAddress(), d.getAddress()); // {A,B,C,D} View a2 = View.create(a.getAddress(), 7, a.getAddress(), b.getAddress(), c.getAddress()); // {A,B,C} View a3 = View.create(a.getAddress(), 8, a.getAddress(), b.getAddress()); // {A,B} View a4 = View.create(a.getAddress(), 9, a.getAddress()); // {A} View b1 = View.create(b.getAddress(), 7, b.getAddress(), c.getAddress(), d.getAddress()); View b2 = View.create(b.getAddress(), 8, b.getAddress(), c.getAddress()); View b3 = View.create(b.getAddress(), 9, b.getAddress()); Util.close(c, d); // not interested in those... // A and B cannot communicate: discard(true, a, b); // inject view A|6={A} into A and B|5={B} into B injectView(a4, a); injectView(b3, b); assert a.getView().equals(a4); assert b.getView().equals(b3); List<Event> merge_events = new ArrayList<>(); for (View view : Arrays.asList(a3, a4, a2, a1)) { MERGE3.MergeHeader hdr = MERGE3.MergeHeader.createInfo(view.getViewId(), null, null); Message msg = new Message(null, a.getAddress(), null).putHeader(merge_id, hdr); merge_events.add(new Event(Event.MSG, msg)); } for (View view : Arrays.asList(b2, b3, b1)) { MERGE3.MergeHeader hdr = MERGE3.MergeHeader.createInfo(view.getViewId(), null, null); Message msg = new Message(null, b.getAddress(), null).putHeader(merge_id, hdr); merge_events.add(new Event(Event.MSG, msg)); } // A and B can communicate again discard(false, a, b); injectMergeEvents(merge_events, a, b); checkInconsistencies(a, b); // merge will happen between A and B Util.waitUntilAllChannelsHaveSameSize(10000, 500, a, b); System.out.println("A's view: " + a.getView() + "\nB's view: " + b.getView()); assert a.getView().size() == 2; assert a.getView().containsMember(a.getAddress()); assert a.getView().containsMember(b.getAddress()); assert a.getView().equals(b.getView()); for (View merge_view : Arrays.asList(getViewFromGMS(a), getViewFromGMS(b))) { System.out.println(merge_view); assert merge_view instanceof MergeView; List<View> subviews = ((MergeView) merge_view).getSubgroups(); assert subviews.size() == 2; } }
public void testMergeWithAsymetricViewsCoordIsolated() { // Isolate the coord Address coord = a.getView().getCreator(); System.out.println("Isolating coord: " + coord); List<Address> members = new ArrayList<>(); members.add(coord); View coord_view = new View(coord, 4, members); System.out.println("coord_view: " + coord_view); Channel coord_channel = findChannel(coord); System.out.println("coord_channel: " + coord_channel.getAddress()); MutableDigest digest = new MutableDigest(coord_view.getMembersRaw()); NAKACK2 nakack = (NAKACK2) coord_channel.getProtocolStack().findProtocol(NAKACK2.class); digest.merge(nakack.getDigest(coord)); GMS gms = (GMS) coord_channel.getProtocolStack().findProtocol(GMS.class); gms.installView(coord_view, digest); System.out.println("gms.getView() " + gms.getView()); System.out.println("Views are:"); for (JChannel ch : Arrays.asList(a, b, c, d)) System.out.println(ch.getAddress() + ": " + ch.getView()); JChannel merge_leader = findChannel(coord); MyReceiver receiver = new MyReceiver(); merge_leader.setReceiver(receiver); System.out.println("merge_leader: " + merge_leader.getAddressAsString()); System.out.println("Injecting MERGE event into merge leader " + merge_leader.getAddress()); Map<Address, View> merge_views = new HashMap<>(4); merge_views.put(a.getAddress(), a.getView()); merge_views.put(b.getAddress(), b.getView()); merge_views.put(c.getAddress(), c.getView()); merge_views.put(d.getAddress(), d.getView()); gms = (GMS) merge_leader.getProtocolStack().findProtocol(GMS.class); gms.up(new Event(Event.MERGE, merge_views)); Util.waitUntilAllChannelsHaveSameSize(10000, 1000, a, b, c, d); System.out.println("Views are:"); for (JChannel ch : Arrays.asList(a, b, c, d)) { View view = ch.getView(); System.out.println(ch.getAddress() + ": " + view); assert view.size() == 4; } MergeView merge_view = receiver.getView(); System.out.println("merge_view = " + merge_view); assert merge_view.size() == 4; assert merge_view.getSubgroups().size() == 2; for (View view : merge_view.getSubgroups()) assert contains(view, a.getAddress()) || contains(view, b.getAddress(), c.getAddress(), d.getAddress()); }
/** * Creates a list of randomly generated partitions, each having a max size of max_partition_size */ protected List<View> createPartitions(int max_partition_size, JChannel... channels) { long view_id = 1; for (JChannel ch : channels) view_id = Math.max(view_id, ch.getView().getViewId().getId()); List<View> partitions = new ArrayList<>(); List<Address> tmp = new ArrayList<>(); for (JChannel ch : channels) tmp.add(ch.getAddress()); while (!tmp.isEmpty()) { int num_to_remove = (int) Util.random(max_partition_size); List<Address> part = new ArrayList<>(max_partition_size); for (int x = 0; x < num_to_remove && !tmp.isEmpty(); x++) part.add(tmp.remove(0)); partitions.add(new View(part.get(0), view_id + 1, part)); } return partitions; }
/** * Takes a membership of 10, e.g. {A,B,C,D,E,F,G,H,I,J}, creates multiple partitions (e.g. * {A,B,C}, {D}, {E,F,G,H}, {I,J}), and merges them back into one cluster. Asserts that there's * only 1 MergeView */ public void testMultipleSplits() throws Exception { e = createChannel("E", true); f = createChannel("F", true); g = createChannel("G", true); h = createChannel("H", true); i = createChannel("I", true); j = createChannel("J", true); Util.waitUntilAllChannelsHaveSameSize(10000, 500, a, b, c, d, e, f, g, h, i, j); enableInfoSender(false, a, b, c, d, e, f, g, h, i, j); // stops INFO sending in MERGE3 for (JChannel ch : Arrays.asList(a, b, c, d, e, f, g, h, i, j)) System.out.println(ch.getName() + ": " + ch.getView()); List<View> partitions = createPartitions(4, a, b, c, d, e, f, g, h, i, j); // Install views for (View partition : partitions) { for (Address mbr : partition.getMembersRaw()) { JChannel ch = findChannel(mbr); injectView(partition, ch); } } System.out.printf("\n%d partitions:\n", partitions.size()); for (JChannel ch : Arrays.asList(a, b, c, d, e, f, g, h, i, j)) System.out.println(ch.getName() + ": " + ch.getView()); System.out.println("\nEnabling INFO sending in merge protocols to merge subclusters"); enableInfoSender(true, a, b, c, d, e, f, g, h, i, j); Util.waitUntilAllChannelsHaveSameSize(30000, 1000, a, b, c, d, e, f, g, h, i, j); System.out.println("\nResulting views:"); for (JChannel ch : Arrays.asList(a, b, c, d, e, f, g, h, i, j)) { GMS gms = (GMS) ch.getProtocolStack().findProtocol(GMS.class); View mv = gms.view(); System.out.println(mv); } for (JChannel ch : Arrays.asList(a, b, c, d, e, f, g, h, i, j)) { GMS gms = (GMS) ch.getProtocolStack().findProtocol(GMS.class); View mv = gms.view(); assert mv instanceof MergeView; assert mv.size() == 10; assert ((MergeView) mv).getSubgroups().size() == partitions.size(); } for (JChannel ch : Arrays.asList(a, b, c, d, e, f, g, h, i, j)) { View view = ch.getView(); assert view.size() == 10 : "view should have 10 members: " + view; } }
protected List<Address> getMembers(JChannel... channels) { List<Address> members = new ArrayList<>(channels.length); for (JChannel ch : channels) members.add(ch.getAddress()); return members; }
protected static boolean contains(View view, Address... members) { List<Address> mbrs = view.getMembers(); for (Address member : members) if (!mbrs.contains(member)) return false; return true; }