Skip to content

Commit 1d74eac

Browse files
committed
PHOENIX-7838 LogicalTableNameBaseIT wrap admin.snapshot() in retry helper
1 parent 132411c commit 1d74eac

1 file changed

Lines changed: 82 additions & 4 deletions

File tree

phoenix-core/src/it/java/org/apache/phoenix/end2end/LogicalTableNameBaseIT.java

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.junit.Assert.assertNotNull;
2727
import static org.junit.Assert.assertTrue;
2828

29+
import java.io.IOException;
2930
import java.sql.Connection;
3031
import java.sql.DriverManager;
3132
import java.sql.PreparedStatement;
@@ -37,10 +38,14 @@
3738
import java.util.Map;
3839
import java.util.Properties;
3940
import java.util.Random;
41+
import java.util.concurrent.TimeUnit;
42+
import java.util.regex.Pattern;
4043
import org.apache.hadoop.hbase.TableName;
4144
import org.apache.hadoop.hbase.client.Admin;
4245
import org.apache.hadoop.hbase.client.Put;
46+
import org.apache.hadoop.hbase.client.SnapshotDescription;
4347
import org.apache.hadoop.hbase.client.Table;
48+
import org.apache.hadoop.hbase.snapshot.SnapshotCreationException;
4449
import org.apache.hadoop.hbase.util.Bytes;
4550
import org.apache.phoenix.coprocessorclient.BaseScannerRegionObserverConstants;
4651
import org.apache.phoenix.jdbc.PhoenixConnection;
@@ -68,6 +73,79 @@ public abstract class LogicalTableNameBaseIT extends BaseTest {
6873
public static final String NEW_TABLE_PREFIX = "NEW_TBL_";
6974
private Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
7075

76+
/**
77+
* Take a snapshot, retrying if the master rejects the request because another snapshot for the
78+
* same table is already in flight. The "already running another snapshot on the same table"
79+
* rejection is most commonly produced by RPC-level retries: the original Admin.snapshot() RPC
80+
* has been accepted by the master and the snapshot procedure is in flight, but the client
81+
* retried the call and the master rejects the duplicate. In that case we poll listSnapshots()
82+
* until the snapshot we wanted appears (or until we time out and try again from scratch). This
83+
* keeps these snapshot+clone tests deterministic on slower or busy hardware.
84+
*/
85+
protected static void snapshotWithRetry(Admin admin, String snapshotName, TableName tableName)
86+
throws IOException {
87+
final long alreadyRunningWaitMs = TimeUnit.MINUTES.toMillis(2L);
88+
final int maxAttempts = 5;
89+
final long backoffMs = 1000L;
90+
IOException lastError = null;
91+
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
92+
try {
93+
admin.snapshot(snapshotName, tableName);
94+
return;
95+
} catch (SnapshotCreationException e) {
96+
if (!isAlreadyRunningSnapshot(e)) {
97+
throw e;
98+
}
99+
if (waitForSnapshotToAppear(admin, snapshotName, alreadyRunningWaitMs)) {
100+
return;
101+
}
102+
lastError = e;
103+
}
104+
try {
105+
Thread.sleep(backoffMs);
106+
} catch (InterruptedException ie) {
107+
Thread.currentThread().interrupt();
108+
break;
109+
}
110+
}
111+
if (lastError != null) {
112+
throw lastError;
113+
}
114+
}
115+
116+
private static boolean isAlreadyRunningSnapshot(Throwable t) {
117+
for (Throwable cur = t; cur != null; cur = cur.getCause()) {
118+
String msg = cur.getMessage();
119+
if (msg != null && msg.contains("already running another snapshot on the same table")) {
120+
return true;
121+
}
122+
}
123+
return false;
124+
}
125+
126+
private static boolean waitForSnapshotToAppear(Admin admin, String snapshotName, long timeoutMs) {
127+
long deadline = System.currentTimeMillis() + timeoutMs;
128+
Pattern pattern = Pattern.compile(Pattern.quote(snapshotName));
129+
while (System.currentTimeMillis() < deadline) {
130+
try {
131+
for (SnapshotDescription d : admin.listSnapshots(pattern)) {
132+
if (snapshotName.equals(d.getName())) {
133+
return true;
134+
}
135+
}
136+
} catch (IOException ioe) {
137+
// transient; keep polling
138+
}
139+
try {
140+
Thread.sleep(500L);
141+
} catch (InterruptedException ie) {
142+
Thread.currentThread().interrupt();
143+
return false;
144+
}
145+
}
146+
return false;
147+
}
148+
71149
static void initCluster(boolean isNamespaceMapped) throws Exception {
72150
Map<String, String> props = Maps.newConcurrentMap();
73151
props.put(QueryServices.DROP_METADATA_ATTRIB, Boolean.TRUE.toString());
@@ -105,7 +183,7 @@ public static void createAndPointToNewPhysicalTable(Connection conn, String full
105183

106184
try (Admin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) {
107185

108-
admin.snapshot(snapshotName, TableName.valueOf(fullTableHName));
186+
snapshotWithRetry(admin, snapshotName, TableName.valueOf(fullTableHName));
109187
admin.cloneSnapshot(snapshotName, TableName.valueOf(fullNewTableHName));
110188
admin.deleteSnapshot(snapshotName);
111189
LogicalTableNameIT.renameAndDropPhysicalTable(conn, null, schemaName, tableName, newTableName,
@@ -130,7 +208,7 @@ protected HashMap<String, ArrayList<String>> testBaseTableWithIndex_BaseTableCha
130208
String fullNewTableName = SchemaUtil.getTableName(schemaName, newTableName);
131209
try (Admin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) {
132210
String snapshotName = new StringBuilder(fullTableName).append("-Snapshot").toString();
133-
admin.snapshot(snapshotName, TableName.valueOf(fullTableName));
211+
snapshotWithRetry(admin, snapshotName, TableName.valueOf(fullTableName));
134212
admin.cloneSnapshot(snapshotName, TableName.valueOf(fullNewTableName));
135213
admin.deleteSnapshot(snapshotName);
136214
try (Table htable = conn.unwrap(PhoenixConnection.class).getQueryServices()
@@ -185,7 +263,7 @@ protected HashMap<String, ArrayList<String>> test_IndexTableChange(Connection co
185263
}
186264
try (Admin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) {
187265
String snapshotName = new StringBuilder(indexName).append("-Snapshot").toString();
188-
admin.snapshot(snapshotName, TableName.valueOf(fullIndexTableHbaseName));
266+
snapshotWithRetry(admin, snapshotName, TableName.valueOf(fullIndexTableHbaseName));
189267
admin.cloneSnapshot(snapshotName, TableName.valueOf(fullNewTableName));
190268
admin.deleteSnapshot(snapshotName);
191269
try (Table htable = conn.unwrap(PhoenixConnection.class).getQueryServices()
@@ -245,7 +323,7 @@ protected HashMap<String, ArrayList<String>> testWithViewsAndIndex_BaseTableChan
245323
}
246324
try (Admin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) {
247325
String snapshotName = new StringBuilder(fullTableName).append("-Snapshot").toString();
248-
admin.snapshot(snapshotName, TableName.valueOf(fullTableHbaseName));
326+
snapshotWithRetry(admin, snapshotName, TableName.valueOf(fullTableHbaseName));
249327
admin.cloneSnapshot(snapshotName, TableName.valueOf(fullNewTableName));
250328
admin.deleteSnapshot(snapshotName);
251329
try (Table htable = conn.unwrap(PhoenixConnection.class).getQueryServices()

0 commit comments

Comments
 (0)