1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Set;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.ConcurrentSkipListMap;
27 import java.util.concurrent.ConcurrentSkipListSet;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.hbase.HConstants;
32 import org.apache.hadoop.hbase.HRegionInfo;
33 import org.apache.hadoop.hbase.HRegionLocation;
34 import org.apache.hadoop.hbase.RegionLocations;
35 import org.apache.hadoop.hbase.ServerName;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.util.Bytes;
38
39
40
41
42 @InterfaceAudience.Private
43 public class MetaCache {
44
45 private static final Log LOG = LogFactory.getLog(MetaCache.class);
46
47
48
49
50 private final ConcurrentMap<TableName, ConcurrentSkipListMap<byte[], RegionLocations>>
51 cachedRegionLocations =
52 new ConcurrentHashMap<TableName, ConcurrentSkipListMap<byte[], RegionLocations>>();
53
54
55
56
57
58
59 private final Set<ServerName> cachedServers = new ConcurrentSkipListSet<ServerName>();
60
61
62
63
64
65
66
67
68
69
70 public RegionLocations getCachedLocation(final TableName tableName, final byte [] row) {
71 ConcurrentSkipListMap<byte[], RegionLocations> tableLocations =
72 getTableLocations(tableName);
73
74 Entry<byte[], RegionLocations> e = tableLocations.floorEntry(row);
75 if (e == null) {
76 return null;
77 }
78 RegionLocations possibleRegion = e.getValue();
79
80
81
82
83
84
85 byte[] endKey = possibleRegion.getRegionLocation().getRegionInfo().getEndKey();
86 if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) ||
87 tableName.getRowComparator().compareRows(
88 endKey, 0, endKey.length, row, 0, row.length) > 0) {
89 return possibleRegion;
90 }
91
92
93 return null;
94 }
95
96
97
98
99
100
101
102 public void cacheLocation(final TableName tableName, final ServerName source,
103 final HRegionLocation location) {
104 assert source != null;
105 byte [] startKey = location.getRegionInfo().getStartKey();
106 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
107 RegionLocations locations = new RegionLocations(new HRegionLocation[] {location}) ;
108 RegionLocations oldLocations = tableLocations.putIfAbsent(startKey, locations);
109 boolean isNewCacheEntry = (oldLocations == null);
110 if (isNewCacheEntry) {
111 if (LOG.isTraceEnabled()) {
112 LOG.trace("Cached location: " + location);
113 }
114 addToCachedServers(locations);
115 return;
116 }
117
118
119 HRegionLocation oldLocation = oldLocations.getRegionLocation(
120 location.getRegionInfo().getReplicaId());
121 boolean force = oldLocation != null && oldLocation.getServerName() != null
122 && oldLocation.getServerName().equals(source);
123
124
125
126
127
128
129 RegionLocations updatedLocations = oldLocations.updateLocation(location, false, force);
130 if (oldLocations != updatedLocations) {
131 boolean replaced = tableLocations.replace(startKey, oldLocations, updatedLocations);
132 if (replaced && LOG.isTraceEnabled()) {
133 LOG.trace("Changed cached location to: " + location);
134 }
135 addToCachedServers(updatedLocations);
136 }
137 }
138
139
140
141
142
143
144 public void cacheLocation(final TableName tableName, final RegionLocations locations) {
145 byte [] startKey = locations.getRegionLocation().getRegionInfo().getStartKey();
146 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
147 RegionLocations oldLocation = tableLocations.putIfAbsent(startKey, locations);
148 boolean isNewCacheEntry = (oldLocation == null);
149 if (isNewCacheEntry) {
150 if (LOG.isTraceEnabled()) {
151 LOG.trace("Cached location: " + locations);
152 }
153 addToCachedServers(locations);
154 return;
155 }
156
157
158
159
160 RegionLocations mergedLocation = oldLocation.mergeLocations(locations);
161 boolean replaced = tableLocations.replace(startKey, oldLocation, mergedLocation);
162 if (replaced && LOG.isTraceEnabled()) {
163 LOG.trace("Merged cached locations: " + mergedLocation);
164 }
165 addToCachedServers(locations);
166 }
167
168 private void addToCachedServers(RegionLocations locations) {
169 for (HRegionLocation loc : locations.getRegionLocations()) {
170 if (loc != null) {
171 cachedServers.add(loc.getServerName());
172 }
173 }
174 }
175
176
177
178
179
180 private ConcurrentSkipListMap<byte[], RegionLocations>
181 getTableLocations(final TableName tableName) {
182
183 ConcurrentSkipListMap<byte[], RegionLocations> result;
184 result = this.cachedRegionLocations.get(tableName);
185
186 if (result == null) {
187 result = new ConcurrentSkipListMap<byte[], RegionLocations>(Bytes.BYTES_COMPARATOR);
188 ConcurrentSkipListMap<byte[], RegionLocations> old =
189 this.cachedRegionLocations.putIfAbsent(tableName, result);
190 if (old != null) {
191 return old;
192 }
193 }
194 return result;
195 }
196
197
198
199
200
201
202
203 public boolean isRegionCached(TableName tableName, final byte[] row) {
204 RegionLocations location = getCachedLocation(tableName, row);
205 return location != null;
206 }
207
208
209
210
211
212 public int getNumberOfCachedRegionLocations(final TableName tableName) {
213 Map<byte[], RegionLocations> tableLocs = this.cachedRegionLocations.get(tableName);
214 if (tableLocs == null) {
215 return 0;
216 }
217 int numRegions = 0;
218 for (RegionLocations tableLoc : tableLocs.values()) {
219 numRegions += tableLoc.numNonNullElements();
220 }
221 return numRegions;
222 }
223
224
225
226
227 public void clearCache() {
228 this.cachedRegionLocations.clear();
229 this.cachedServers.clear();
230 }
231
232
233
234
235 public void clearCache(final ServerName serverName) {
236 if (!this.cachedServers.contains(serverName)) {
237 return;
238 }
239
240 boolean deletedSomething = false;
241 synchronized (this.cachedServers) {
242
243
244
245
246 if (!this.cachedServers.contains(serverName)) {
247 return;
248 }
249 for (ConcurrentMap<byte[], RegionLocations> tableLocations : cachedRegionLocations.values()){
250 for (Entry<byte[], RegionLocations> e : tableLocations.entrySet()) {
251 RegionLocations regionLocations = e.getValue();
252 if (regionLocations != null) {
253 RegionLocations updatedLocations = regionLocations.removeByServer(serverName);
254 if (updatedLocations != regionLocations) {
255 if (updatedLocations.isEmpty()) {
256 deletedSomething |= tableLocations.remove(e.getKey(), regionLocations);
257 } else {
258 deletedSomething |= tableLocations.replace(e.getKey(), regionLocations, updatedLocations);
259 }
260 }
261 }
262 }
263 }
264 this.cachedServers.remove(serverName);
265 }
266 if (deletedSomething && LOG.isTraceEnabled()) {
267 LOG.trace("Removed all cached region locations that map to " + serverName);
268 }
269 }
270
271
272
273
274 public void clearCache(final TableName tableName) {
275 if (LOG.isTraceEnabled()) {
276 LOG.trace("Removed all cached region locations for table " + tableName);
277 }
278 this.cachedRegionLocations.remove(tableName);
279 }
280
281
282
283
284
285
286 public void clearCache(final TableName tableName, final byte [] row, int replicaId) {
287 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
288
289 boolean removed = false;
290 RegionLocations regionLocations = getCachedLocation(tableName, row);
291 if (regionLocations != null) {
292 HRegionLocation toBeRemoved = regionLocations.getRegionLocation(replicaId);
293 RegionLocations updatedLocations = regionLocations.remove(replicaId);
294 if (updatedLocations != regionLocations) {
295 byte[] startKey = regionLocations.getRegionLocation().getRegionInfo().getStartKey();
296 if (updatedLocations.isEmpty()) {
297 removed = tableLocations.remove(startKey, regionLocations);
298 } else {
299 removed = tableLocations.replace(startKey, regionLocations, updatedLocations);
300 }
301 }
302
303 if (removed && LOG.isTraceEnabled() && toBeRemoved != null) {
304 LOG.trace("Removed " + toBeRemoved + " from cache");
305 }
306 }
307 }
308
309
310
311
312
313
314 public void clearCache(final TableName tableName, final byte [] row) {
315 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
316
317 RegionLocations regionLocations = getCachedLocation(tableName, row);
318 if (regionLocations != null) {
319 byte[] startKey = regionLocations.getRegionLocation().getRegionInfo().getStartKey();
320 boolean removed = tableLocations.remove(startKey, regionLocations);
321 if (removed && LOG.isTraceEnabled()) {
322 LOG.trace("Removed " + regionLocations + " from cache");
323 }
324 }
325 }
326
327
328
329
330 public void clearCache(final TableName tableName, final byte [] row, ServerName serverName) {
331 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
332
333 RegionLocations regionLocations = getCachedLocation(tableName, row);
334 if (regionLocations != null) {
335 RegionLocations updatedLocations = regionLocations.removeByServer(serverName);
336 if (updatedLocations != regionLocations) {
337 byte[] startKey = regionLocations.getRegionLocation().getRegionInfo().getStartKey();
338 boolean removed = false;
339 if (updatedLocations.isEmpty()) {
340 removed = tableLocations.remove(startKey, regionLocations);
341 } else {
342 removed = tableLocations.replace(startKey, regionLocations, updatedLocations);
343 }
344 if (removed && LOG.isTraceEnabled()) {
345 LOG.trace("Removed locations of table: " + tableName + " ,row: " + Bytes.toString(row)
346 + " mapping to server: " + serverName + " from cache");
347 }
348 }
349 }
350 }
351
352
353
354
355
356 public void clearCache(HRegionInfo hri) {
357 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(hri.getTable());
358 RegionLocations regionLocations = tableLocations.get(hri.getStartKey());
359 if (regionLocations != null) {
360 HRegionLocation oldLocation = regionLocations.getRegionLocation(hri.getReplicaId());
361 if (oldLocation == null) return;
362 RegionLocations updatedLocations = regionLocations.remove(oldLocation);
363 boolean removed = false;
364 if (updatedLocations != regionLocations) {
365 if (updatedLocations.isEmpty()) {
366 removed = tableLocations.remove(hri.getStartKey(), regionLocations);
367 } else {
368 removed = tableLocations.replace(hri.getStartKey(), regionLocations, updatedLocations);
369 }
370 if (removed && LOG.isTraceEnabled()) {
371 LOG.trace("Removed " + oldLocation + " from cache");
372 }
373 }
374 }
375 }
376
377 public void clearCache(final HRegionLocation location) {
378 if (location == null) {
379 return;
380 }
381 TableName tableName = location.getRegionInfo().getTable();
382 ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
383 RegionLocations regionLocations = tableLocations.get(location.getRegionInfo().getStartKey());
384 if (regionLocations != null) {
385 RegionLocations updatedLocations = regionLocations.remove(location);
386 boolean removed = false;
387 if (updatedLocations != regionLocations) {
388 if (updatedLocations.isEmpty()) {
389 removed = tableLocations.remove(location.getRegionInfo().getStartKey(), regionLocations);
390 } else {
391 removed = tableLocations.replace(location.getRegionInfo().getStartKey(), regionLocations, updatedLocations);
392 }
393 if (removed && LOG.isTraceEnabled()) {
394 LOG.trace("Removed " + location + " from cache");
395 }
396 }
397 }
398 }
399 }