Adds a new region to our regions cache. @param meta_row The (parsed) result of the RegionClient#getClosestRowBefore request sent to the .META. (or -ROOT-) table. @return The client serving the region we discovered, or null if this region isn't being served right now (and we marked it
(final ArrayList<KeyValue> meta_row)
| 3187 | * this region isn't being served right now (and we marked it as NSRE'd). |
| 3188 | */ |
| 3189 | RegionClient discoverRegion(final ArrayList<KeyValue> meta_row) { |
| 3190 | if (meta_row.isEmpty()) { |
| 3191 | throw new TableNotFoundException(); |
| 3192 | } |
| 3193 | String host = null; |
| 3194 | int port = -42; |
| 3195 | RegionInfo region = null; |
| 3196 | byte[] start_key = null; |
| 3197 | for (final KeyValue kv : meta_row) { |
| 3198 | final byte[] qualifier = kv.qualifier(); |
| 3199 | if (Arrays.equals(REGIONINFO, qualifier)) { |
| 3200 | final byte[][] tmp = new byte[1][]; // Yes, this is ugly. |
| 3201 | region = RegionInfo.fromKeyValue(kv, tmp); |
| 3202 | if (knownToBeNSREd(region)) { |
| 3203 | invalidateRegionCache(region.name(), true, "has marked it as split."); |
| 3204 | return null; |
| 3205 | } |
| 3206 | start_key = tmp[0]; |
| 3207 | } else if (Arrays.equals(SERVER, qualifier) |
| 3208 | && kv.value() != EMPTY_ARRAY) { // Empty during NSRE. |
| 3209 | final byte[] hostport = kv.value(); |
| 3210 | int colon = hostport.length - 1; |
| 3211 | for (/**/; colon > 0 /* Can't be at the beginning */; colon--) { |
| 3212 | if (hostport[colon] == ':') { |
| 3213 | break; |
| 3214 | } |
| 3215 | } |
| 3216 | if (colon == 0) { |
| 3217 | throw BrokenMetaException.badKV(region, "an `info:server' cell" |
| 3218 | + " doesn't contain `:' to separate the `host:port'" |
| 3219 | + Bytes.pretty(hostport), kv); |
| 3220 | } |
| 3221 | host = getIP(new String(hostport, 0, colon)); |
| 3222 | try { |
| 3223 | port = parsePortNumber(new String(hostport, colon + 1, |
| 3224 | hostport.length - colon - 1)); |
| 3225 | } catch (NumberFormatException e) { |
| 3226 | throw BrokenMetaException.badKV(region, "an `info:server' cell" |
| 3227 | + " contains an invalid port: " + e.getMessage() + " in " |
| 3228 | + Bytes.pretty(hostport), kv); |
| 3229 | } |
| 3230 | } |
| 3231 | // TODO(tsuna): If this is the parent of a split region, there are two |
| 3232 | // other KVs that could be useful: `info:splitA' and `info:splitB'. |
| 3233 | // Need to investigate whether we can use those as a hint to update our |
| 3234 | // regions_cache with the daughter regions of the split. |
| 3235 | } |
| 3236 | if (start_key == null) { |
| 3237 | throw new BrokenMetaException("It didn't contain any" |
| 3238 | + " `info:regioninfo' cell: " + meta_row); |
| 3239 | } |
| 3240 | |
| 3241 | final byte[] region_name = region.name(); |
| 3242 | if (host == null) { |
| 3243 | // When there's no `info:server' cell, it typically means that the |
| 3244 | // location of this region is about to be updated in META, so we |
| 3245 | // consider this as an NSRE. |
| 3246 | invalidateRegionCache(region_name, true, "no longer has it assigned."); |
no test coverage detected