001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.replication; 019 020import static org.junit.Assert.assertNull; 021import static org.junit.Assert.assertTrue; 022import static org.mockito.Mockito.mock; 023import static org.mockito.Mockito.when; 024 025import java.util.ArrayList; 026import java.util.HashMap; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.TreeMap; 032import org.apache.hadoop.hbase.Cell; 033import org.apache.hadoop.hbase.CellComparatorImpl; 034import org.apache.hadoop.hbase.HBaseClassTestRule; 035import org.apache.hadoop.hbase.HConstants; 036import org.apache.hadoop.hbase.KeyValue; 037import org.apache.hadoop.hbase.TableName; 038import org.apache.hadoop.hbase.client.RegionInfoBuilder; 039import org.apache.hadoop.hbase.testclassification.ReplicationTests; 040import org.apache.hadoop.hbase.testclassification.SmallTests; 041import org.apache.hadoop.hbase.util.Bytes; 042import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 043import org.apache.hadoop.hbase.wal.WAL.Entry; 044import org.apache.hadoop.hbase.wal.WALEdit; 045import org.apache.hadoop.hbase.wal.WALKeyImpl; 046import org.junit.Assert; 047import org.junit.ClassRule; 048import org.junit.Test; 049import org.junit.experimental.categories.Category; 050 051import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 052 053@Category({ ReplicationTests.class, SmallTests.class }) 054public class TestReplicationWALEntryFilters { 055 056 @ClassRule 057 public static final HBaseClassTestRule CLASS_RULE = 058 HBaseClassTestRule.forClass(TestReplicationWALEntryFilters.class); 059 060 static byte[] a = new byte[] { 'a' }; 061 static byte[] b = new byte[] { 'b' }; 062 static byte[] c = new byte[] { 'c' }; 063 static byte[] d = new byte[] { 'd' }; 064 065 @Test 066 public void testSystemTableWALEntryFilter() { 067 SystemTableWALEntryFilter filter = new SystemTableWALEntryFilter(); 068 069 // meta 070 WALKeyImpl key1 = 071 new WALKeyImpl(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedNameAsBytes(), 072 TableName.META_TABLE_NAME, EnvironmentEdgeManager.currentTime()); 073 Entry metaEntry = new Entry(key1, null); 074 075 assertNull(filter.filter(metaEntry)); 076 077 // user table 078 WALKeyImpl key3 = 079 new WALKeyImpl(new byte[0], TableName.valueOf("foo"), EnvironmentEdgeManager.currentTime()); 080 Entry userEntry = new Entry(key3, null); 081 082 assertEquals(userEntry, filter.filter(userEntry)); 083 } 084 085 @Test 086 public void testScopeWALEntryFilter() { 087 WALEntryFilter filter = new ChainWALEntryFilter(new ScopeWALEntryFilter()); 088 089 Entry userEntry = createEntry(null, a, b); 090 Entry userEntryA = createEntry(null, a); 091 Entry userEntryB = createEntry(null, b); 092 Entry userEntryEmpty = createEntry(null); 093 094 // no scopes 095 // now we will not filter out entries without a replication scope since serial replication still 096 // need the sequence id, but the cells will all be filtered out. 097 assertTrue(filter.filter(userEntry).getEdit().isEmpty()); 098 099 // empty scopes 100 // ditto 101 TreeMap<byte[], Integer> scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 102 userEntry = createEntry(scopes, a, b); 103 assertTrue(filter.filter(userEntry).getEdit().isEmpty()); 104 105 // different scope 106 scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 107 scopes.put(c, HConstants.REPLICATION_SCOPE_GLOBAL); 108 userEntry = createEntry(scopes, a, b); 109 // all kvs should be filtered 110 assertEquals(userEntryEmpty, filter.filter(userEntry)); 111 112 // local scope 113 scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 114 scopes.put(a, HConstants.REPLICATION_SCOPE_LOCAL); 115 userEntry = createEntry(scopes, a, b); 116 assertEquals(userEntryEmpty, filter.filter(userEntry)); 117 scopes.put(b, HConstants.REPLICATION_SCOPE_LOCAL); 118 assertEquals(userEntryEmpty, filter.filter(userEntry)); 119 120 // only scope a 121 scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 122 scopes.put(a, HConstants.REPLICATION_SCOPE_GLOBAL); 123 userEntry = createEntry(scopes, a, b); 124 assertEquals(userEntryA, filter.filter(userEntry)); 125 scopes.put(b, HConstants.REPLICATION_SCOPE_LOCAL); 126 assertEquals(userEntryA, filter.filter(userEntry)); 127 128 // only scope b 129 scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 130 scopes.put(b, HConstants.REPLICATION_SCOPE_GLOBAL); 131 userEntry = createEntry(scopes, a, b); 132 assertEquals(userEntryB, filter.filter(userEntry)); 133 scopes.put(a, HConstants.REPLICATION_SCOPE_LOCAL); 134 assertEquals(userEntryB, filter.filter(userEntry)); 135 136 // scope a and b 137 scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR); 138 scopes.put(b, HConstants.REPLICATION_SCOPE_GLOBAL); 139 userEntry = createEntry(scopes, a, b); 140 assertEquals(userEntryB, filter.filter(userEntry)); 141 scopes.put(a, HConstants.REPLICATION_SCOPE_LOCAL); 142 assertEquals(userEntryB, filter.filter(userEntry)); 143 } 144 145 WALEntryFilter nullFilter = new WALEntryFilter() { 146 @Override 147 public Entry filter(Entry entry) { 148 return null; 149 } 150 }; 151 152 WALEntryFilter passFilter = new WALEntryFilter() { 153 @Override 154 public Entry filter(Entry entry) { 155 return entry; 156 } 157 }; 158 159 public static class FilterSomeCellsWALCellFilter implements WALEntryFilter, WALCellFilter { 160 @Override 161 public Entry filter(Entry entry) { 162 return entry; 163 } 164 165 @Override 166 public Cell filterCell(Entry entry, Cell cell) { 167 if ( 168 Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()).equals("a") 169 ) { 170 return null; 171 } else { 172 return cell; 173 } 174 } 175 } 176 177 public static class FilterAllCellsWALCellFilter implements WALEntryFilter, WALCellFilter { 178 @Override 179 public Entry filter(Entry entry) { 180 return entry; 181 } 182 183 @Override 184 public Cell filterCell(Entry entry, Cell cell) { 185 return null; 186 } 187 } 188 189 @Test 190 public void testChainWALEntryWithCellFilter() { 191 Entry userEntry = createEntry(null, a, b, c); 192 ChainWALEntryFilter filterSomeCells = 193 new ChainWALEntryFilter(new FilterSomeCellsWALCellFilter()); 194 // since WALCellFilter filter cells with rowkey 'a' 195 assertEquals(createEntry(null, b, c), filterSomeCells.filter(userEntry)); 196 197 Entry userEntry2 = createEntry(null, b, c, d); 198 // since there is no cell to get filtered, nothing should get filtered 199 assertEquals(userEntry2, filterSomeCells.filter(userEntry2)); 200 201 // since we filter all the cells, we should get empty entry 202 ChainWALEntryFilter filterAllCells = new ChainWALEntryFilter(new FilterAllCellsWALCellFilter()); 203 assertEquals(createEntry(null), filterAllCells.filter(userEntry)); 204 } 205 206 @Test 207 public void testChainWALEmptyEntryWithCellFilter() { 208 Entry userEntry = createEntry(null, a, b, c); 209 ChainWALEmptyEntryFilter filterSomeCells = 210 new ChainWALEmptyEntryFilter(new FilterSomeCellsWALCellFilter()); 211 // since WALCellFilter filter cells with rowkey 'a' 212 assertEquals(createEntry(null, b, c), filterSomeCells.filter(userEntry)); 213 214 Entry userEntry2 = createEntry(null, b, c, d); 215 // since there is no cell to get filtered, nothing should get filtered 216 assertEquals(userEntry2, filterSomeCells.filter(userEntry2)); 217 218 ChainWALEmptyEntryFilter filterAllCells = 219 new ChainWALEmptyEntryFilter(new FilterAllCellsWALCellFilter()); 220 assertEquals(createEntry(null), filterAllCells.filter(userEntry)); 221 // let's set the filter empty entry flag to true now for the above case 222 filterAllCells.setFilterEmptyEntry(true); 223 // since WALCellFilter filter all cells, whole entry should be filtered 224 assertEquals(null, filterAllCells.filter(userEntry)); 225 } 226 227 @Test 228 public void testChainWALEntryFilter() { 229 Entry userEntry = createEntry(null, a, b, c); 230 231 ChainWALEntryFilter filter = new ChainWALEntryFilter(passFilter); 232 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 233 234 filter = new ChainWALEntryFilter(passFilter, passFilter); 235 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 236 237 filter = new ChainWALEntryFilter(passFilter, passFilter, passFilter); 238 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 239 240 filter = new ChainWALEntryFilter(nullFilter); 241 assertEquals(null, filter.filter(userEntry)); 242 243 filter = new ChainWALEntryFilter(nullFilter, passFilter); 244 assertEquals(null, filter.filter(userEntry)); 245 246 filter = new ChainWALEntryFilter(passFilter, nullFilter); 247 assertEquals(null, filter.filter(userEntry)); 248 249 filter = new ChainWALEntryFilter(nullFilter, passFilter, nullFilter); 250 assertEquals(null, filter.filter(userEntry)); 251 252 filter = new ChainWALEntryFilter(nullFilter, nullFilter); 253 assertEquals(null, filter.filter(userEntry)); 254 255 // flatten 256 filter = new ChainWALEntryFilter( 257 new ChainWALEntryFilter(passFilter, new ChainWALEntryFilter(passFilter, passFilter), 258 new ChainWALEntryFilter(passFilter), new ChainWALEntryFilter(passFilter)), 259 new ChainWALEntryFilter(passFilter)); 260 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 261 262 filter = new ChainWALEntryFilter( 263 new ChainWALEntryFilter(passFilter, 264 new ChainWALEntryFilter(passFilter, new ChainWALEntryFilter(nullFilter))), 265 new ChainWALEntryFilter(passFilter)); 266 assertEquals(null, filter.filter(userEntry)); 267 } 268 269 @Test 270 public void testNamespaceTableCfWALEntryFilter() { 271 ReplicationPeer peer = mock(ReplicationPeer.class); 272 ReplicationPeerConfigBuilder peerConfigBuilder = ReplicationPeerConfig.newBuilder(); 273 274 // 1. replicate_all flag is false, no namespaces and table-cfs config 275 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(null).setTableCFsMap(null); 276 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 277 Entry userEntry = createEntry(null, a, b, c); 278 ChainWALEntryFilter filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 279 assertEquals(null, filter.filter(userEntry)); 280 281 // 2. replicate_all flag is false, and only config table-cfs in peer 282 // empty map 283 userEntry = createEntry(null, a, b, c); 284 Map<TableName, List<String>> tableCfs = new HashMap<>(); 285 peerConfigBuilder.setReplicateAllUserTables(false).setTableCFsMap(tableCfs); 286 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 287 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 288 assertEquals(null, filter.filter(userEntry)); 289 290 // table bar 291 userEntry = createEntry(null, a, b, c); 292 tableCfs = new HashMap<>(); 293 tableCfs.put(TableName.valueOf("bar"), null); 294 peerConfigBuilder.setReplicateAllUserTables(false).setTableCFsMap(tableCfs); 295 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 296 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 297 assertEquals(null, filter.filter(userEntry)); 298 299 // table foo:a 300 userEntry = createEntry(null, a, b, c); 301 tableCfs = new HashMap<>(); 302 tableCfs.put(TableName.valueOf("foo"), Lists.newArrayList("a")); 303 peerConfigBuilder.setReplicateAllUserTables(false).setTableCFsMap(tableCfs); 304 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 305 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 306 assertEquals(createEntry(null, a), filter.filter(userEntry)); 307 308 // table foo:a,c 309 userEntry = createEntry(null, a, b, c, d); 310 tableCfs = new HashMap<>(); 311 tableCfs.put(TableName.valueOf("foo"), Lists.newArrayList("a", "c")); 312 peerConfigBuilder.setReplicateAllUserTables(false).setTableCFsMap(tableCfs); 313 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 314 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 315 assertEquals(createEntry(null, a, c), filter.filter(userEntry)); 316 317 // 3. replicate_all flag is false, and only config namespaces in peer 318 when(peer.getTableCFs()).thenReturn(null); 319 // empty set 320 Set<String> namespaces = new HashSet<>(); 321 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(namespaces) 322 .setTableCFsMap(null); 323 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 324 userEntry = createEntry(null, a, b, c); 325 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 326 assertEquals(null, filter.filter(userEntry)); 327 328 // namespace default 329 namespaces.add("default"); 330 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(namespaces); 331 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 332 userEntry = createEntry(null, a, b, c); 333 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 334 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 335 336 // namespace ns1 337 namespaces = new HashSet<>(); 338 namespaces.add("ns1"); 339 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(namespaces); 340 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 341 userEntry = createEntry(null, a, b, c); 342 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 343 assertEquals(null, filter.filter(userEntry)); 344 345 // 4. replicate_all flag is false, and config namespaces and table-cfs both 346 // Namespaces config should not confict with table-cfs config 347 namespaces = new HashSet<>(); 348 tableCfs = new HashMap<>(); 349 namespaces.add("ns1"); 350 tableCfs.put(TableName.valueOf("foo"), Lists.newArrayList("a", "c")); 351 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(namespaces) 352 .setTableCFsMap(tableCfs); 353 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 354 userEntry = createEntry(null, a, b, c); 355 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 356 assertEquals(createEntry(null, a, c), filter.filter(userEntry)); 357 358 namespaces = new HashSet<>(); 359 tableCfs = new HashMap<>(); 360 namespaces.add("default"); 361 tableCfs.put(TableName.valueOf("ns1:foo"), Lists.newArrayList("a", "c")); 362 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(namespaces) 363 .setTableCFsMap(tableCfs); 364 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 365 userEntry = createEntry(null, a, b, c); 366 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 367 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 368 369 namespaces = new HashSet<>(); 370 tableCfs = new HashMap<>(); 371 namespaces.add("ns1"); 372 tableCfs.put(TableName.valueOf("bar"), null); 373 peerConfigBuilder.setReplicateAllUserTables(false).setNamespaces(namespaces) 374 .setTableCFsMap(tableCfs); 375 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 376 userEntry = createEntry(null, a, b, c); 377 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 378 assertEquals(null, filter.filter(userEntry)); 379 } 380 381 @Test 382 public void testNamespaceTableCfWALEntryFilter2() { 383 ReplicationPeer peer = mock(ReplicationPeer.class); 384 ReplicationPeerConfigBuilder peerConfigBuilder = ReplicationPeerConfig.newBuilder(); 385 386 // 1. replicate_all flag is true 387 // and no exclude namespaces and no exclude table-cfs config 388 peerConfigBuilder.setReplicateAllUserTables(true).setExcludeNamespaces(null) 389 .setExcludeTableCFsMap(null); 390 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 391 Entry userEntry = createEntry(null, a, b, c); 392 ChainWALEntryFilter filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 393 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 394 395 // 2. replicate_all flag is true, and only config exclude namespaces 396 // empty set 397 Set<String> namespaces = new HashSet<String>(); 398 peerConfigBuilder.setExcludeNamespaces(namespaces).setExcludeTableCFsMap(null); 399 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 400 userEntry = createEntry(null, a, b, c); 401 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 402 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 403 404 // exclude namespace default 405 namespaces.add("default"); 406 peerConfigBuilder.setExcludeNamespaces(namespaces).setExcludeTableCFsMap(null); 407 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 408 userEntry = createEntry(null, a, b, c); 409 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 410 assertEquals(null, filter.filter(userEntry)); 411 412 // exclude namespace ns1 413 namespaces = new HashSet<String>(); 414 namespaces.add("ns1"); 415 peerConfigBuilder.setExcludeNamespaces(namespaces).setExcludeTableCFsMap(null); 416 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 417 userEntry = createEntry(null, a, b, c); 418 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 419 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 420 421 // 3. replicate_all flag is true, and only config exclude table-cfs 422 // empty table-cfs map 423 Map<TableName, List<String>> tableCfs = new HashMap<TableName, List<String>>(); 424 peerConfigBuilder.setExcludeNamespaces(null).setExcludeTableCFsMap(tableCfs); 425 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 426 userEntry = createEntry(null, a, b, c); 427 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 428 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 429 430 // exclude table bar 431 tableCfs = new HashMap<TableName, List<String>>(); 432 tableCfs.put(TableName.valueOf("bar"), null); 433 peerConfigBuilder.setExcludeNamespaces(null).setExcludeTableCFsMap(tableCfs); 434 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 435 userEntry = createEntry(null, a, b, c); 436 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 437 assertEquals(createEntry(null, a, b, c), filter.filter(userEntry)); 438 439 // exclude table foo:a 440 tableCfs = new HashMap<TableName, List<String>>(); 441 tableCfs.put(TableName.valueOf("foo"), Lists.newArrayList("a")); 442 peerConfigBuilder.setExcludeNamespaces(null).setExcludeTableCFsMap(tableCfs); 443 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 444 userEntry = createEntry(null, a, b, c); 445 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 446 assertEquals(createEntry(null, b, c), filter.filter(userEntry)); 447 448 // 4. replicate_all flag is true, and config exclude namespaces and table-cfs both 449 // exclude ns1 and table foo:a,c 450 namespaces = new HashSet<String>(); 451 tableCfs = new HashMap<TableName, List<String>>(); 452 namespaces.add("ns1"); 453 tableCfs.put(TableName.valueOf("foo"), Lists.newArrayList("a", "c")); 454 peerConfigBuilder.setExcludeNamespaces(namespaces).setExcludeTableCFsMap(tableCfs); 455 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 456 userEntry = createEntry(null, a, b, c); 457 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 458 assertEquals(createEntry(null, b), filter.filter(userEntry)); 459 460 // exclude namespace default and table ns1:bar 461 namespaces = new HashSet<String>(); 462 tableCfs = new HashMap<TableName, List<String>>(); 463 namespaces.add("default"); 464 tableCfs.put(TableName.valueOf("ns1:bar"), new ArrayList<String>()); 465 peerConfigBuilder.setExcludeNamespaces(namespaces).setExcludeTableCFsMap(tableCfs); 466 when(peer.getPeerConfig()).thenReturn(peerConfigBuilder.build()); 467 userEntry = createEntry(null, a, b, c); 468 filter = new ChainWALEntryFilter(new NamespaceTableCfWALEntryFilter(peer)); 469 assertEquals(null, filter.filter(userEntry)); 470 } 471 472 private Entry createEntry(TreeMap<byte[], Integer> scopes, byte[]... kvs) { 473 WALKeyImpl key1 = new WALKeyImpl(new byte[0], TableName.valueOf("foo"), 474 EnvironmentEdgeManager.currentTime(), scopes); 475 WALEdit edit1 = new WALEdit(); 476 477 for (byte[] kv : kvs) { 478 edit1.add(new KeyValue(kv, kv, kv)); 479 } 480 return new Entry(key1, edit1); 481 } 482 483 private void assertEquals(Entry e1, Entry e2) { 484 Assert.assertEquals(e1 == null, e2 == null); 485 if (e1 == null) { 486 return; 487 } 488 489 // do not compare WALKeys 490 491 // compare kvs 492 Assert.assertEquals(e1.getEdit() == null, e2.getEdit() == null); 493 if (e1.getEdit() == null) { 494 return; 495 } 496 List<Cell> cells1 = e1.getEdit().getCells(); 497 List<Cell> cells2 = e2.getEdit().getCells(); 498 Assert.assertEquals(cells1.size(), cells2.size()); 499 for (int i = 0; i < cells1.size(); i++) { 500 CellComparatorImpl.COMPARATOR.compare(cells1.get(i), cells2.get(i)); 501 } 502 } 503}