Skip to content

Commit e3d6204

Browse files
author
Ed Coleman
committed
Merge remote-tracking branch 'upstream/2.1'
- merge FateIT into main - includes minor quality check fixes
2 parents 4886e82 + 00bac7a commit e3d6204

File tree

1 file changed

+139
-21
lines changed
  • test/src/main/java/org/apache/accumulo/test/fate/zookeeper

1 file changed

+139
-21
lines changed

test/src/main/java/org/apache/accumulo/test/fate/zookeeper/FateIT.java

+139-21
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import static org.junit.jupiter.api.Assertions.fail;
3737

3838
import java.io.File;
39+
import java.util.ArrayList;
40+
import java.util.List;
3941
import java.util.UUID;
4042
import java.util.concurrent.CountDownLatch;
4143

@@ -114,19 +116,77 @@ public Repo<Manager> call(long tid, Manager manager) throws Exception {
114116

115117
}
116118

119+
public static class TestOperationFails extends ManagerRepo {
120+
private static final long serialVersionUID = 1L;
121+
private static final Logger LOG = LoggerFactory.getLogger(TestOperationFails.class);
122+
private static List<String> undoOrder = new ArrayList<>();
123+
private static final int TOTAL_NUM_OPS = 3;
124+
private int opNum;
125+
private final String opName;
126+
private final ExceptionLocation location;
127+
128+
public TestOperationFails(int opNum, ExceptionLocation location) {
129+
this.opNum = opNum;
130+
this.opName = "OP" + opNum;
131+
this.location = location;
132+
}
133+
134+
@Override
135+
public long isReady(long tid, Manager environment) throws Exception {
136+
LOG.debug("{} {} Entered isReady()", opName, FateTxId.formatTid(tid));
137+
if (location == ExceptionLocation.IS_READY) {
138+
if (opNum < TOTAL_NUM_OPS) {
139+
return 0;
140+
} else {
141+
throw new Exception(
142+
opName + " " + FateTxId.formatTid(tid) + " isReady() failed - this is expected");
143+
}
144+
} else {
145+
return 0;
146+
}
147+
}
148+
149+
@Override
150+
public void undo(long tid, Manager environment) throws Exception {
151+
LOG.debug("{} {} Entered undo()", opName, FateTxId.formatTid(tid));
152+
undoOrder.add(opName);
153+
undoLatch.countDown();
154+
}
155+
156+
@Override
157+
public Repo<Manager> call(long tid, Manager environment) throws Exception {
158+
LOG.debug("{} {} Entered call()", opName, FateTxId.formatTid(tid));
159+
if (location == ExceptionLocation.CALL) {
160+
if (opNum < TOTAL_NUM_OPS) {
161+
return new TestOperationFails(++opNum, location);
162+
} else {
163+
throw new Exception(
164+
opName + " " + FateTxId.formatTid(tid) + " call() failed - this is expected");
165+
}
166+
} else {
167+
return new TestOperationFails(++opNum, location);
168+
}
169+
}
170+
}
171+
117172
private static final Logger LOG = LoggerFactory.getLogger(FateIT.class);
118173

119174
@TempDir
120175
private static File tempDir;
121176

122177
private static ZooKeeperTestingServer szk = null;
123178
private static ZooReaderWriter zk = null;
124-
private static final String ZK_ROOT = "/accumulo/" + UUID.randomUUID().toString();
179+
private static final String ZK_ROOT = "/accumulo/" + UUID.randomUUID();
125180
private static final NamespaceId NS = NamespaceId.of("testNameSpace");
126181
private static final TableId TID = TableId.of("testTable");
127182

128183
private static CountDownLatch callStarted;
129184
private static CountDownLatch finishCall;
185+
private static CountDownLatch undoLatch;
186+
187+
private enum ExceptionLocation {
188+
CALL, IS_READY
189+
}
130190

131191
@BeforeAll
132192
public static void setup() throws Exception {
@@ -148,9 +208,8 @@ public static void teardown() throws Exception {
148208
@Timeout(30)
149209
public void testTransactionStatus() throws Exception {
150210

151-
final ZooStore<Manager> zooStore = new ZooStore<Manager>(ZK_ROOT + Constants.ZFATE, zk);
152-
final AgeOffStore<Manager> store =
153-
new AgeOffStore<Manager>(zooStore, 3000, System::currentTimeMillis);
211+
final ZooStore<Manager> zooStore = new ZooStore<>(ZK_ROOT + Constants.ZFATE, zk);
212+
final AgeOffStore<Manager> store = new AgeOffStore<>(zooStore, 3000, System::currentTimeMillis);
154213

155214
Manager manager = createMock(Manager.class);
156215
ServerContext sctx = createMock(ServerContext.class);
@@ -162,19 +221,20 @@ public void testTransactionStatus() throws Exception {
162221
ConfigurationCopy config = new ConfigurationCopy();
163222
config.set(Property.GENERAL_THREADPOOL_SIZE, "2");
164223
config.set(Property.MANAGER_FATE_THREADPOOL_SIZE, "1");
165-
Fate<Manager> fate = new Fate<Manager>(manager, store, TraceRepo::toLogString, config);
224+
Fate<Manager> fate = new Fate<>(manager, store, TraceRepo::toLogString, config);
166225
try {
167226

168-
// Wait for the transaction runner to be scheduled.
169-
Thread.sleep(3000);
170-
171227
callStarted = new CountDownLatch(1);
172228
finishCall = new CountDownLatch(1);
173229

174230
long txid = fate.startTransaction();
175231
assertEquals(TStatus.NEW, getTxStatus(zk, txid));
176232
fate.seedTransaction("TestOperation", txid, new TestOperation(NS, TID), true, "Test Op");
177233
assertEquals(TStatus.SUBMITTED, getTxStatus(zk, txid));
234+
235+
// Wait for the transaction runner to be scheduled.
236+
Thread.sleep(3000);
237+
178238
// wait for call() to be called
179239
callStarted.await();
180240
assertEquals(IN_PROGRESS, getTxStatus(zk, txid));
@@ -208,9 +268,8 @@ public void testTransactionStatus() throws Exception {
208268

209269
@Test
210270
public void testCancelWhileNew() throws Exception {
211-
final ZooStore<Manager> zooStore = new ZooStore<Manager>(ZK_ROOT + Constants.ZFATE, zk);
212-
final AgeOffStore<Manager> store =
213-
new AgeOffStore<Manager>(zooStore, 3000, System::currentTimeMillis);
271+
final ZooStore<Manager> zooStore = new ZooStore<>(ZK_ROOT + Constants.ZFATE, zk);
272+
final AgeOffStore<Manager> store = new AgeOffStore<>(zooStore, 3000, System::currentTimeMillis);
214273

215274
Manager manager = createMock(Manager.class);
216275
ServerContext sctx = createMock(ServerContext.class);
@@ -222,9 +281,8 @@ public void testCancelWhileNew() throws Exception {
222281
ConfigurationCopy config = new ConfigurationCopy();
223282
config.set(Property.GENERAL_THREADPOOL_SIZE, "2");
224283
config.set(Property.MANAGER_FATE_THREADPOOL_SIZE, "1");
225-
Fate<Manager> fate = new Fate<Manager>(manager, store, TraceRepo::toLogString, config);
284+
Fate<Manager> fate = new Fate<>(manager, store, TraceRepo::toLogString, config);
226285
try {
227-
228286
// Wait for the transaction runner to be scheduled.
229287
Thread.sleep(3000);
230288

@@ -250,9 +308,8 @@ public void testCancelWhileNew() throws Exception {
250308

251309
@Test
252310
public void testCancelWhileSubmittedAndRunning() throws Exception {
253-
final ZooStore<Manager> zooStore = new ZooStore<Manager>(ZK_ROOT + Constants.ZFATE, zk);
254-
final AgeOffStore<Manager> store =
255-
new AgeOffStore<Manager>(zooStore, 3000, System::currentTimeMillis);
311+
final ZooStore<Manager> zooStore = new ZooStore<>(ZK_ROOT + Constants.ZFATE, zk);
312+
final AgeOffStore<Manager> store = new AgeOffStore<>(zooStore, 3000, System::currentTimeMillis);
256313

257314
Manager manager = createMock(Manager.class);
258315
ServerContext sctx = createMock(ServerContext.class);
@@ -264,7 +321,7 @@ public void testCancelWhileSubmittedAndRunning() throws Exception {
264321
ConfigurationCopy config = new ConfigurationCopy();
265322
config.set(Property.GENERAL_THREADPOOL_SIZE, "2");
266323
config.set(Property.MANAGER_FATE_THREADPOOL_SIZE, "1");
267-
Fate<Manager> fate = new Fate<Manager>(manager, store, TraceRepo::toLogString, config);
324+
Fate<Manager> fate = new Fate<>(manager, store, TraceRepo::toLogString, config);
268325
try {
269326

270327
// Wait for the transaction runner to be scheduled.
@@ -293,9 +350,8 @@ public void testCancelWhileSubmittedAndRunning() throws Exception {
293350

294351
@Test
295352
public void testCancelWhileInCall() throws Exception {
296-
final ZooStore<Manager> zooStore = new ZooStore<Manager>(ZK_ROOT + Constants.ZFATE, zk);
297-
final AgeOffStore<Manager> store =
298-
new AgeOffStore<Manager>(zooStore, 3000, System::currentTimeMillis);
353+
final ZooStore<Manager> zooStore = new ZooStore<>(ZK_ROOT + Constants.ZFATE, zk);
354+
final AgeOffStore<Manager> store = new AgeOffStore<>(zooStore, 3000, System::currentTimeMillis);
299355

300356
Manager manager = createMock(Manager.class);
301357
ServerContext sctx = createMock(ServerContext.class);
@@ -307,7 +363,7 @@ public void testCancelWhileInCall() throws Exception {
307363
ConfigurationCopy config = new ConfigurationCopy();
308364
config.set(Property.GENERAL_THREADPOOL_SIZE, "2");
309365
config.set(Property.MANAGER_FATE_THREADPOOL_SIZE, "1");
310-
Fate<Manager> fate = new Fate<Manager>(manager, store, TraceRepo::toLogString, config);
366+
Fate<Manager> fate = new Fate<>(manager, store, TraceRepo::toLogString, config);
311367
try {
312368

313369
// Wait for the transaction runner to be scheduled.
@@ -321,6 +377,7 @@ public void testCancelWhileInCall() throws Exception {
321377
assertEquals(NEW, getTxStatus(zk, txid));
322378
fate.seedTransaction("TestOperation", txid, new TestOperation(NS, TID), true, "Test Op");
323379
assertEquals(SUBMITTED, getTxStatus(zk, txid));
380+
324381
// wait for call() to be called
325382
callStarted.await();
326383
// cancel the transaction
@@ -331,6 +388,67 @@ public void testCancelWhileInCall() throws Exception {
331388

332389
}
333390

391+
@Test
392+
public void testRepoFails() throws Exception {
393+
/*
394+
* This test ensures that when an exception occurs in a Repo's call() or isReady() methods, that
395+
* undo() will be called back up the chain of Repo's and in the correct order. The test works as
396+
* follows: 1) Repo1 is called and returns Repo2, 2) Repo2 is called and returns Repo3, 3) Repo3
397+
* is called and throws an exception (in call() or isReady()). It is then expected that: 1)
398+
* undo() is called on Repo3, 2) undo() is called on Repo2, 3) undo() is called on Repo1
399+
*/
400+
final ZooStore<Manager> zooStore = new ZooStore<>(ZK_ROOT + Constants.ZFATE, zk);
401+
final AgeOffStore<Manager> store = new AgeOffStore<>(zooStore, 3000, System::currentTimeMillis);
402+
403+
Manager manager = createMock(Manager.class);
404+
ServerContext sctx = createMock(ServerContext.class);
405+
expect(manager.getContext()).andReturn(sctx).anyTimes();
406+
expect(sctx.getZooKeeperRoot()).andReturn(ZK_ROOT).anyTimes();
407+
expect(sctx.getZooReaderWriter()).andReturn(zk).anyTimes();
408+
replay(manager, sctx);
409+
410+
ConfigurationCopy config = new ConfigurationCopy();
411+
config.set(Property.GENERAL_THREADPOOL_SIZE, "2");
412+
config.set(Property.MANAGER_FATE_THREADPOOL_SIZE, "1");
413+
Fate<Manager> fate = new Fate<>(manager, store, TraceRepo::toLogString, config);
414+
try {
415+
416+
// Wait for the transaction runner to be scheduled.
417+
Thread.sleep(3000);
418+
419+
List<String> expectedUndoOrder = List.of("OP3", "OP2", "OP1");
420+
/*
421+
* Test exception in call()
422+
*/
423+
undoLatch = new CountDownLatch(TestOperationFails.TOTAL_NUM_OPS);
424+
long txid = fate.startTransaction();
425+
assertEquals(NEW, getTxStatus(zk, txid));
426+
fate.seedTransaction("TestOperationFails", txid,
427+
new TestOperationFails(1, ExceptionLocation.CALL), false, "Test Op Fails");
428+
// Wait for all the undo() calls to complete
429+
undoLatch.await();
430+
assertEquals(expectedUndoOrder, TestOperationFails.undoOrder);
431+
assertEquals(FAILED, fate.waitForCompletion(txid));
432+
assertTrue(fate.getException(txid).getMessage().contains("call() failed"));
433+
/*
434+
* Test exception in isReady()
435+
*/
436+
TestOperationFails.undoOrder = new ArrayList<>();
437+
undoLatch = new CountDownLatch(TestOperationFails.TOTAL_NUM_OPS);
438+
txid = fate.startTransaction();
439+
assertEquals(NEW, getTxStatus(zk, txid));
440+
fate.seedTransaction("TestOperationFails", txid,
441+
new TestOperationFails(1, ExceptionLocation.IS_READY), false, "Test Op Fails");
442+
// Wait for all the undo() calls to complete
443+
undoLatch.await();
444+
assertEquals(expectedUndoOrder, TestOperationFails.undoOrder);
445+
assertEquals(FAILED, fate.waitForCompletion(txid));
446+
assertTrue(fate.getException(txid).getMessage().contains("isReady() failed"));
447+
} finally {
448+
fate.shutdown();
449+
}
450+
}
451+
334452
private static void inCall() throws InterruptedException {
335453
// signal that call started
336454
callStarted.countDown();

0 commit comments

Comments
 (0)