18
18
*/
19
19
package org .apache .accumulo .test .functional ;
20
20
21
+ import static org .apache .accumulo .core .manager .state .TabletManagement .ManagementAction .NEEDS_LOCATION_UPDATE ;
21
22
import static org .junit .jupiter .api .Assertions .assertEquals ;
22
23
23
24
import java .io .IOException ;
24
25
import java .time .Duration ;
25
26
import java .util .ArrayList ;
26
27
import java .util .Collections ;
28
+ import java .util .HashMap ;
27
29
import java .util .HashSet ;
28
30
import java .util .Iterator ;
29
31
import java .util .List ;
@@ -141,15 +143,30 @@ public void test() throws AccumuloException, AccumuloSecurityException, TableExi
141
143
// examine a clone of the metadata table, so we can manipulate it
142
144
copyTable (client , AccumuloTable .METADATA .tableName (), metaCopy1 );
143
145
146
+ var tableId1 = getServerContext ().getTableId (t1 );
147
+ var tableId3 = getServerContext ().getTableId (t3 );
148
+ var tableId4 = getServerContext ().getTableId (t4 );
149
+
150
+ // Create expected KeyExtents to test output of findTabletsNeedingAttention
151
+ KeyExtent endR1 = new KeyExtent (tableId1 , new Text ("some split" ), null );
152
+ KeyExtent endR3 = new KeyExtent (tableId3 , new Text ("some split" ), null );
153
+ KeyExtent endR4 = new KeyExtent (tableId4 , new Text ("some split" ), null );
154
+ KeyExtent prevR1 = new KeyExtent (tableId1 , null , new Text ("some split" ));
155
+ KeyExtent prevR3 = new KeyExtent (tableId3 , null , new Text ("some split" ));
156
+ KeyExtent prevR4 = new KeyExtent (tableId4 , null , new Text ("some split" ));
157
+ Map <KeyExtent ,Set <TabletManagement .ManagementAction >> expected ;
158
+
144
159
TabletManagementParameters tabletMgmtParams = createParameters (client );
145
- int tabletsInFlux = findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams );
146
- while (tabletsInFlux > 0 ) {
160
+ Map <KeyExtent ,Set <TabletManagement .ManagementAction >> tabletsInFlux =
161
+ findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams );
162
+ while (!tabletsInFlux .isEmpty ()) {
147
163
log .debug ("Waiting for {} tablets for {}" , tabletsInFlux , metaCopy1 );
148
164
UtilWaitThread .sleep (500 );
149
165
copyTable (client , AccumuloTable .METADATA .tableName (), metaCopy1 );
150
166
tabletsInFlux = findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams );
151
167
}
152
- assertEquals (0 , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
168
+ expected = Map .of ();
169
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
153
170
"No tables should need attention" );
154
171
155
172
// The metadata table stabilized and metaCopy1 contains a copy suitable for testing. Before
@@ -165,72 +182,93 @@ public void test() throws AccumuloException, AccumuloSecurityException, TableExi
165
182
// t3 is hosted, setting to never will generate a change to unhost tablets
166
183
setTabletAvailability (client , metaCopy1 , t3 , TabletAvailability .UNHOSTED .name ());
167
184
tabletMgmtParams = createParameters (client );
168
- assertEquals (4 , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
185
+ expected = Map .of (endR1 , Set .of (NEEDS_LOCATION_UPDATE ), prevR1 , Set .of (NEEDS_LOCATION_UPDATE ),
186
+ endR3 , Set .of (NEEDS_LOCATION_UPDATE ), prevR3 , Set .of (NEEDS_LOCATION_UPDATE ));
187
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
169
188
"Should have four tablets with hosting availability changes" );
170
189
171
190
// test the assigned case (no location)
172
191
removeLocation (client , metaCopy1 , t3 );
173
- assertEquals (2 , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
192
+ expected =
193
+ Map .of (endR1 , Set .of (NEEDS_LOCATION_UPDATE ), prevR1 , Set .of (NEEDS_LOCATION_UPDATE ));
194
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
174
195
"Should have two tablets without a loc" );
175
196
176
197
// Test setting the operation id on one of the tablets in table t1. Table t1 has two tablets
177
198
// w/o a location. Only one should need attention because of the operation id.
178
199
setOperationId (client , metaCopy1 , t1 , new Text ("some split" ), TabletOperationType .SPLITTING );
179
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
200
+ expected = Map .of (prevR1 , Set .of (NEEDS_LOCATION_UPDATE ));
201
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy1 , tabletMgmtParams ),
180
202
"Should have tablets needing attention because of operation id" );
181
203
182
204
// test the cases where the assignment is to a dead tserver
183
205
reassignLocation (client , metaCopy2 , t3 );
184
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy2 , tabletMgmtParams ),
206
+ expected = Map .of (endR3 , Set .of (NEEDS_LOCATION_UPDATE ));
207
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy2 , tabletMgmtParams ),
185
208
"Only 1 of 2 tablets in table t1 should be returned" );
186
209
187
210
// Test the recovery cases
188
211
createLogEntry (client , metaCopy5 , t1 );
189
212
setTabletAvailability (client , metaCopy5 , t1 , TabletAvailability .UNHOSTED .name ());
190
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy5 , tabletMgmtParams ),
213
+ expected = Map .of (endR1 ,
214
+ Set .of (NEEDS_LOCATION_UPDATE , TabletManagement .ManagementAction .NEEDS_RECOVERY ));
215
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy5 , tabletMgmtParams ),
191
216
"Only 1 of 2 tablets in table t1 should be returned" );
192
217
setTabletAvailability (client , metaCopy5 , t1 , TabletAvailability .ONDEMAND .name ());
193
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy5 , tabletMgmtParams ),
218
+ expected = Map .of (endR1 ,
219
+ Set .of (NEEDS_LOCATION_UPDATE , TabletManagement .ManagementAction .NEEDS_RECOVERY ));
220
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy5 , tabletMgmtParams ),
194
221
"Only 1 of 2 tablets in table t1 should be returned" );
195
222
setTabletAvailability (client , metaCopy5 , t1 , TabletAvailability .HOSTED .name ());
196
- assertEquals (2 , findTabletsNeedingAttention (client , metaCopy5 , tabletMgmtParams ),
223
+ expected = Map .of (endR1 ,
224
+ Set .of (NEEDS_LOCATION_UPDATE , TabletManagement .ManagementAction .NEEDS_RECOVERY ), prevR1 ,
225
+ Set .of (NEEDS_LOCATION_UPDATE ));
226
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy5 , tabletMgmtParams ),
197
227
"2 tablets in table t1 should be returned" );
198
228
199
229
// Remove location and set merge operation id on both tablets
200
230
// These tablets should not need attention as they have no WALs
201
231
setTabletAvailability (client , metaCopy4 , t4 , TabletAvailability .HOSTED .name ());
202
232
removeLocation (client , metaCopy4 , t4 );
203
- assertEquals (2 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
233
+ expected =
234
+ Map .of (endR4 , Set .of (NEEDS_LOCATION_UPDATE ), prevR4 , Set .of (NEEDS_LOCATION_UPDATE ));
235
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
204
236
"Tablets have no location and a tablet availability of hosted, so they should need attention" );
205
237
206
238
// Test MERGING and SPLITTING do not need attention with no location or wals
207
239
setOperationId (client , metaCopy4 , t4 , null , TabletOperationType .MERGING );
208
- assertEquals (0 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
240
+ expected = Map .of ();
241
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
209
242
"Should have no tablets needing attention for merge as they have no location" );
210
243
setOperationId (client , metaCopy4 , t4 , null , TabletOperationType .SPLITTING );
211
- assertEquals (0 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
244
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
212
245
"Should have no tablets needing attention for merge as they have no location" );
213
246
214
247
// Create a log entry for one of the tablets, this tablet will now need attention
215
248
// for both MERGING and SPLITTING
216
249
setOperationId (client , metaCopy4 , t4 , null , TabletOperationType .MERGING );
217
250
createLogEntry (client , metaCopy4 , t4 );
218
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
251
+ expected = Map .of (endR4 ,
252
+ Set .of (NEEDS_LOCATION_UPDATE , TabletManagement .ManagementAction .NEEDS_RECOVERY ));
253
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
219
254
"Should have a tablet needing attention because of wals" );
220
255
// Switch op to SPLITTING which should also need attention like MERGING
221
256
setOperationId (client , metaCopy4 , t4 , null , TabletOperationType .SPLITTING );
222
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
257
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
223
258
"Should have a tablet needing attention because of wals" );
224
259
225
260
// Switch op to delete, no tablets should need attention even with WALs
226
261
setOperationId (client , metaCopy4 , t4 , null , TabletOperationType .DELETING );
227
- assertEquals (0 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
262
+ expected = Map .of ();
263
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
228
264
"Should have no tablets needing attention for delete" );
229
265
230
266
// test the bad tablet location state case (inconsistent metadata)
231
267
tabletMgmtParams = createParameters (client );
232
268
addDuplicateLocation (client , metaCopy3 , t3 );
233
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy3 , tabletMgmtParams ),
269
+ expected = Map .of (prevR3 ,
270
+ Set .of (NEEDS_LOCATION_UPDATE , TabletManagement .ManagementAction .BAD_STATE ));
271
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy3 , tabletMgmtParams ),
234
272
"Should have 1 tablet that needs a metadata repair" );
235
273
236
274
// test the volume replacements case. Need to insert some files into
@@ -240,25 +278,29 @@ public void test() throws AccumuloException, AccumuloSecurityException, TableExi
240
278
Map <Path ,Path > replacements =
241
279
Map .of (new Path ("file:/vol1/accumulo/inst_id" ), new Path ("file:/vol2/accumulo/inst_id" ));
242
280
tabletMgmtParams = createParameters (client , replacements );
243
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
281
+ expected = Map .of (prevR4 , Set .of (TabletManagement .ManagementAction .NEEDS_VOLUME_REPLACEMENT ));
282
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy4 , tabletMgmtParams ),
244
283
"Should have one tablet that needs a volume replacement" );
245
284
246
285
// In preparation for split an offline testing ensure nothing needs attention
247
286
tabletMgmtParams = createParameters (client );
248
287
addFiles (client , metaCopy6 , t4 );
249
- assertEquals (0 , findTabletsNeedingAttention (client , metaCopy6 , tabletMgmtParams ),
288
+ expected = Map .of ();
289
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy6 , tabletMgmtParams ),
250
290
"No tablets should need attention" );
251
291
// Lower the split threshold for the table, should cause the files added to need attention.
252
292
client .tableOperations ().setProperty (tables [3 ], Property .TABLE_SPLIT_THRESHOLD .getKey (),
253
293
"1K" );
254
- assertEquals (1 , findTabletsNeedingAttention (client , metaCopy6 , tabletMgmtParams ),
294
+ expected = Map .of (prevR4 , Set .of (TabletManagement .ManagementAction .NEEDS_SPLITTING ));
295
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy6 , tabletMgmtParams ),
255
296
"Should have one tablet that needs splitting" );
256
297
257
298
// Take the table offline which should prevent the tablet from being returned for needing to
258
299
// split
259
300
client .tableOperations ().offline (tables [3 ], false );
260
301
tabletMgmtParams = createParameters (client );
261
- assertEquals (0 , findTabletsNeedingAttention (client , metaCopy6 , tabletMgmtParams ),
302
+ expected = Map .of ();
303
+ assertEquals (expected , findTabletsNeedingAttention (client , metaCopy6 , tabletMgmtParams ),
262
304
"No tablets should need attention" );
263
305
264
306
// clean up
@@ -379,17 +421,18 @@ private void removeLocation(AccumuloClient client, String table, String tableNam
379
421
deleter .close ();
380
422
}
381
423
382
- private int findTabletsNeedingAttention (AccumuloClient client , String table ,
383
- TabletManagementParameters tabletMgmtParams ) throws TableNotFoundException , IOException {
384
- int results = 0 ;
424
+ private Map <KeyExtent ,Set <TabletManagement .ManagementAction >> findTabletsNeedingAttention (
425
+ AccumuloClient client , String table , TabletManagementParameters tabletMgmtParams )
426
+ throws TableNotFoundException , IOException {
427
+ Map <KeyExtent ,Set <TabletManagement .ManagementAction >> results = new HashMap <>();
385
428
List <KeyExtent > resultList = new ArrayList <>();
386
429
try (Scanner scanner = client .createScanner (table , Authorizations .EMPTY )) {
387
430
TabletManagementIterator .configureScanner (scanner , tabletMgmtParams );
388
431
scanner .updateScanIteratorOption ("tabletChange" , "debug" , "1" );
389
432
for (Entry <Key ,Value > e : scanner ) {
390
433
if (e != null ) {
391
434
TabletManagement mti = TabletManagementIterator .decode (e );
392
- results ++ ;
435
+ results . put ( mti . getTabletMetadata (). getExtent (), mti . getActions ()) ;
393
436
log .debug ("Found tablets that changed state: {}" , mti .getTabletMetadata ().getExtent ());
394
437
log .debug ("actions : {}" , mti .getActions ());
395
438
log .debug ("metadata: {}" , mti .getTabletMetadata ());
0 commit comments