26
26
import java .net .URI ;
27
27
import java .net .URISyntaxException ;
28
28
import java .net .URL ;
29
+ import java .util .HashMap ;
30
+ import java .util .Map ;
29
31
30
32
import javax .servlet .ServletException ;
31
33
import javax .servlet .annotation .WebServlet ;
36
38
import org .jboss .as .server .CurrentServiceContainer ;
37
39
import org .jboss .msc .service .ServiceController ;
38
40
import org .jboss .msc .service .ServiceName ;
41
+ import org .jgroups .Address ;
39
42
import org .jgroups .Channel ;
43
+ import org .jgroups .Event ;
40
44
import org .jgroups .View ;
41
45
import org .jgroups .protocols .DISCARD ;
42
46
import org .jgroups .protocols .TP ;
43
47
import org .jgroups .protocols .pbcast .GMS ;
44
48
import org .jgroups .stack .ProtocolStack ;
45
49
46
50
/**
47
- * Servlet used to simulate network partitions. Responds to {@code /partitioner?partition=true} by inserting DISCARD protocol to the
48
- * stack and {@code /partitioner?partition=false} by removing previously inserted DISCARD protocol.
51
+ * Servlet used to simulate network partitions. Responds to {@code /partitioner?partition=true} by inserting DISCARD protocol to the stack
52
+ * and installing new view directly on the {@link GMS} and responds to {@code /partitioner?partition=false} by removing previously inserted
53
+ * {@link DISCARD} protocol and passing MERGE event up the stack.
54
+ * <p>
55
+ * Note that while it would be desirable for the tests to leave splitting and merging to the servers themselves, this is not practical in a
56
+ * test suite. While FD/VERIFY_SUSPECT/GMS can be be configured to detect partitions quickly the MERGE3 handles merges within randomized
57
+ * intervals and uses unreliable channel which can easily take several minutes for merge to actually happen. Also, speeds up the test
58
+ * significantly.
49
59
*
50
60
* @author Radoslav Husar
51
61
*/
52
62
@ WebServlet (urlPatterns = {PartitionerServlet .SERVLET_PATH })
53
63
public class PartitionerServlet extends HttpServlet {
54
64
65
+ private static final long VIEWS_TIMEOUT = 3_000 ;
55
66
public static final String SERVLET_PATH = "partitioner" ;
56
67
private static final String PARTITION = "partition" ;
57
68
69
+ private static Map <Address , View > mergeViews ;
70
+
58
71
public static URI createURI (URL baseURL , boolean partition ) throws URISyntaxException {
59
72
return baseURL .toURI ().resolve (SERVLET_PATH + '?' + PARTITION + '=' + partition );
60
73
}
@@ -71,17 +84,35 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
71
84
Channel channel = service .awaitValue ();
72
85
73
86
if (partition ) {
87
+ // Store views for future merge event
88
+ GMS gms = (GMS ) channel .getProtocolStack ().findProtocol (GMS .class );
89
+ mergeViews = new HashMap <>();
90
+ channel .getView ().getMembers ().forEach (
91
+ address -> mergeViews .put (address , View .create (address , gms .getViewId ().getId () + 1 , address ))
92
+ );
93
+ // Wait a few seconds to ensure everyone stored a full view
94
+ Thread .sleep (VIEWS_TIMEOUT );
95
+
74
96
// Simulate partitions by injecting DISCARD protocol
75
97
DISCARD discard = new DISCARD ();
76
98
discard .setDiscardAll (true );
77
99
channel .getProtocolStack ().insertProtocol (discard , ProtocolStack .ABOVE , TP .class );
78
100
79
101
// Speed up partitioning
80
- GMS gms = (GMS ) channel .getProtocolStack ().findProtocol (GMS .class );
81
102
View view = View .create (channel .getAddress (), gms .getViewId ().getId () + 1 , channel .getAddress ());
82
103
gms .installView (view );
83
104
} else {
84
105
channel .getProtocolStack ().removeProtocol (DISCARD .class );
106
+ // Wait a few seconds for the other node to remove DISCARD so it does not discard our MERGE request
107
+ Thread .sleep (VIEWS_TIMEOUT );
108
+
109
+ // Since the coordinator is determined by ordering the address in org.jgroups.protocols.pbcast.Merger#determineMergeLeader
110
+ // let just all nodes send the merge..
111
+ this .log ("Passing event up the stack: " + new Event (Event .MERGE , mergeViews ));
112
+
113
+ GMS gms = (GMS ) channel .getProtocolStack ().findProtocol (GMS .class );
114
+ gms .up (new Event (Event .MERGE , mergeViews ));
115
+ mergeViews = null ;
85
116
}
86
117
} catch (Exception e ) {
87
118
throw new ServletException (e );
0 commit comments