1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.util;
21
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.List;
26 import java.util.Map.Entry;
27 import java.util.TreeMap;
28 import java.util.TreeSet;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.util.Bytes.ByteArrayComparator;
33
34 import com.google.common.collect.ArrayListMultimap;
35 import com.google.common.collect.Multimap;
36 import com.google.common.collect.TreeMultimap;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class RegionSplitCalculator<R extends KeyRange> {
55 final static Log LOG = LogFactory.getLog(RegionSplitCalculator.class);
56
57 private final Comparator<R> rangeCmp;
58
59
60
61
62
63
64 private final TreeSet<byte[]> splits = new TreeSet<byte[]>(BYTES_COMPARATOR);
65
66
67
68
69
70
71 private final Multimap<byte[], R> starts = ArrayListMultimap.create();
72
73
74
75
76 private final static byte[] ENDKEY = null;
77
78 public RegionSplitCalculator(Comparator<R> cmp) {
79 rangeCmp = cmp;
80 }
81
82 public final static Comparator<byte[]> BYTES_COMPARATOR = new ByteArrayComparator() {
83 @Override
84 public int compare(byte[] l, byte[] r) {
85 if (l == null && r == null)
86 return 0;
87 if (l == null)
88 return 1;
89 if (r == null)
90 return -1;
91 return super.compare(l, r);
92 }
93 };
94
95
96
97
98
99
100 private static <R extends KeyRange> byte[] specialEndKey(R range) {
101 byte[] end = range.getEndKey();
102 if (end.length == 0) {
103 return ENDKEY;
104 }
105 return end;
106 }
107
108
109
110
111
112
113 public boolean add(R range) {
114 byte[] start = range.getStartKey();
115 byte[] end = specialEndKey(range);
116
117 if (end != ENDKEY && Bytes.compareTo(start, end) > 0) {
118
119 LOG.debug("attempted to add backwards edge: " + Bytes.toString(start)
120 + " " + Bytes.toString(end));
121 return false;
122 }
123
124 splits.add(start);
125 splits.add(end);
126 starts.put(start, range);
127 return true;
128 }
129
130
131
132
133
134
135
136 public Multimap<byte[], R> calcCoverage() {
137
138
139 Multimap<byte[], R> regions = TreeMultimap.create(BYTES_COMPARATOR,
140 rangeCmp);
141
142
143 for (Entry<byte[], Collection<R>> start : starts.asMap().entrySet()) {
144 byte[] key = start.getKey();
145 for (R r : start.getValue()) {
146 regions.put(key, r);
147
148 for (byte[] coveredSplit : splits.subSet(r.getStartKey(),
149 specialEndKey(r))) {
150 regions.put(coveredSplit, r);
151 }
152 }
153 }
154 return regions;
155 }
156
157 public TreeSet<byte[]> getSplits() {
158 return splits;
159 }
160
161 public Multimap<byte[], R> getStarts() {
162 return starts;
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176 public static <R extends KeyRange> List<R>
177 findBigRanges(Collection<R> bigOverlap, int count) {
178 List<R> bigRanges = new ArrayList<R>();
179
180
181
182 TreeMap<Integer, List<R>> overlapRangeMap = new TreeMap<Integer, List<R>>();
183 for (R r: bigOverlap) {
184
185
186 byte[] startKey = r.getStartKey();
187 byte[] endKey = specialEndKey(r);
188
189 int overlappedRegions = 0;
190 for (R rr: bigOverlap) {
191 byte[] start = rr.getStartKey();
192 byte[] end = specialEndKey(rr);
193
194 if (BYTES_COMPARATOR.compare(startKey, end) < 0
195 && BYTES_COMPARATOR.compare(endKey, start) > 0) {
196 overlappedRegions++;
197 }
198 }
199
200
201
202
203 if (overlappedRegions > 1) {
204 Integer key = Integer.valueOf(overlappedRegions);
205 List<R> ranges = overlapRangeMap.get(key);
206 if (ranges == null) {
207 ranges = new ArrayList<R>();
208 overlapRangeMap.put(key, ranges);
209 }
210 ranges.add(r);
211 }
212 }
213 int toBeAdded = count;
214 for (Integer key: overlapRangeMap.descendingKeySet()) {
215 List<R> chunk = overlapRangeMap.get(key);
216 int chunkSize = chunk.size();
217 if (chunkSize <= toBeAdded) {
218 bigRanges.addAll(chunk);
219 toBeAdded -= chunkSize;
220 if (toBeAdded > 0) continue;
221 } else {
222
223
224
225
226 int start = (chunkSize - toBeAdded)/2;
227 int end = start + toBeAdded;
228 for (int i = start; i < end; i++) {
229 bigRanges.add(chunk.get(i));
230 }
231 }
232 break;
233 }
234 return bigRanges;
235 }
236 }