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.regionserver.wal; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.Map; 027import java.util.Set; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HConstants; 030import org.apache.hadoop.hbase.testclassification.SmallTests; 031import org.apache.hadoop.hbase.util.Bytes; 032import org.junit.ClassRule; 033import org.junit.Test; 034import org.junit.experimental.categories.Category; 035 036@Category(SmallTests.class) 037public class TestSequenceIdAccounting { 038 039 @ClassRule 040 public static final HBaseClassTestRule CLASS_RULE = 041 HBaseClassTestRule.forClass(TestSequenceIdAccounting.class); 042 043 private static final byte [] ENCODED_REGION_NAME = Bytes.toBytes("r"); 044 private static final byte [] FAMILY_NAME = Bytes.toBytes("cf"); 045 private static final Set<byte[]> FAMILIES; 046 static { 047 FAMILIES = new HashSet<>(); 048 FAMILIES.add(FAMILY_NAME); 049 } 050 051 @Test 052 public void testStartCacheFlush() { 053 SequenceIdAccounting sida = new SequenceIdAccounting(); 054 sida.getOrCreateLowestSequenceIds(ENCODED_REGION_NAME); 055 Map<byte[], Long> m = new HashMap<>(); 056 m.put(ENCODED_REGION_NAME, HConstants.NO_SEQNUM); 057 assertEquals(HConstants.NO_SEQNUM, (long)sida.startCacheFlush(ENCODED_REGION_NAME, FAMILIES)); 058 sida.completeCacheFlush(ENCODED_REGION_NAME); 059 long sequenceid = 1; 060 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid, true); 061 // Only one family so should return NO_SEQNUM still. 062 assertEquals(HConstants.NO_SEQNUM, (long)sida.startCacheFlush(ENCODED_REGION_NAME, FAMILIES)); 063 sida.completeCacheFlush(ENCODED_REGION_NAME); 064 long currentSequenceId = sequenceid; 065 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid, true); 066 final Set<byte[]> otherFamily = new HashSet<>(1); 067 otherFamily.add(Bytes.toBytes("otherCf")); 068 sida.update(ENCODED_REGION_NAME, FAMILIES, ++sequenceid, true); 069 // Should return oldest sequence id in the region. 070 assertEquals(currentSequenceId, (long)sida.startCacheFlush(ENCODED_REGION_NAME, otherFamily)); 071 sida.completeCacheFlush(ENCODED_REGION_NAME); 072 } 073 074 @Test 075 public void testAreAllLower() { 076 SequenceIdAccounting sida = new SequenceIdAccounting(); 077 sida.getOrCreateLowestSequenceIds(ENCODED_REGION_NAME); 078 Map<byte[], Long> m = new HashMap<>(); 079 m.put(ENCODED_REGION_NAME, HConstants.NO_SEQNUM); 080 assertTrue(sida.areAllLower(m)); 081 long sequenceid = 1; 082 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid, true); 083 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 084 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 085 assertTrue(sida.areAllLower(m)); 086 m.put(ENCODED_REGION_NAME, sequenceid); 087 assertFalse(sida.areAllLower(m)); 088 long lowest = sida.getLowestSequenceId(ENCODED_REGION_NAME); 089 assertEquals("Lowest should be first sequence id inserted", 1, lowest); 090 m.put(ENCODED_REGION_NAME, lowest); 091 assertFalse(sida.areAllLower(m)); 092 // Now make sure above works when flushing. 093 sida.startCacheFlush(ENCODED_REGION_NAME, FAMILIES); 094 assertFalse(sida.areAllLower(m)); 095 m.put(ENCODED_REGION_NAME, HConstants.NO_SEQNUM); 096 assertTrue(sida.areAllLower(m)); 097 // Let the flush complete and if we ask if the sequenceid is lower, should be yes since no edits 098 sida.completeCacheFlush(ENCODED_REGION_NAME); 099 m.put(ENCODED_REGION_NAME, sequenceid); 100 assertTrue(sida.areAllLower(m)); 101 // Flush again but add sequenceids while we are flushing. 102 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 103 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 104 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 105 lowest = sida.getLowestSequenceId(ENCODED_REGION_NAME); 106 m.put(ENCODED_REGION_NAME, lowest); 107 assertFalse(sida.areAllLower(m)); 108 sida.startCacheFlush(ENCODED_REGION_NAME, FAMILIES); 109 // The cache flush will clear out all sequenceid accounting by region. 110 assertEquals(HConstants.NO_SEQNUM, sida.getLowestSequenceId(ENCODED_REGION_NAME)); 111 sida.completeCacheFlush(ENCODED_REGION_NAME); 112 // No new edits have gone in so no sequenceid to work with. 113 assertEquals(HConstants.NO_SEQNUM, sida.getLowestSequenceId(ENCODED_REGION_NAME)); 114 // Make an edit behind all we'll put now into sida. 115 m.put(ENCODED_REGION_NAME, sequenceid); 116 sida.update(ENCODED_REGION_NAME, FAMILIES, ++sequenceid, true); 117 sida.update(ENCODED_REGION_NAME, FAMILIES, ++sequenceid, true); 118 sida.update(ENCODED_REGION_NAME, FAMILIES, ++sequenceid, true); 119 assertTrue(sida.areAllLower(m)); 120 } 121 122 @Test 123 public void testFindLower() { 124 SequenceIdAccounting sida = new SequenceIdAccounting(); 125 sida.getOrCreateLowestSequenceIds(ENCODED_REGION_NAME); 126 Map<byte[], Long> m = new HashMap<>(); 127 m.put(ENCODED_REGION_NAME, HConstants.NO_SEQNUM); 128 long sequenceid = 1; 129 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid, true); 130 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 131 sida.update(ENCODED_REGION_NAME, FAMILIES, sequenceid++, true); 132 assertTrue(sida.findLower(m) == null); 133 m.put(ENCODED_REGION_NAME, sida.getLowestSequenceId(ENCODED_REGION_NAME)); 134 assertTrue(sida.findLower(m).length == 1); 135 m.put(ENCODED_REGION_NAME, sida.getLowestSequenceId(ENCODED_REGION_NAME) - 1); 136 assertTrue(sida.findLower(m) == null); 137 } 138}