| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.accumulo.core.client.admin; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.math.BigInteger; |
| import java.util.Iterator; |
| import java.util.Map.Entry; |
| |
| import org.apache.accumulo.core.client.IteratorSetting; |
| import org.apache.accumulo.core.client.Scanner; |
| import org.apache.accumulo.core.client.TableNotFoundException; |
| import org.apache.accumulo.core.data.Key; |
| import org.apache.accumulo.core.data.PartialKey; |
| import org.apache.accumulo.core.data.Range; |
| import org.apache.accumulo.core.data.Value; |
| import org.apache.accumulo.core.iterators.SortedKeyIterator; |
| import org.apache.hadoop.io.Text; |
| |
| public class FindMax { |
| private static void appendZeros(ByteArrayOutputStream baos, int num) { |
| for (int i = 0; i < num; i++) |
| baos.write(0); |
| } |
| |
| private static Text findMidPoint(Text minBS, Text maxBS) { |
| ByteArrayOutputStream startOS = new ByteArrayOutputStream(); |
| startOS.write(0); // add a leading zero so bigint does not think its negative |
| startOS.write(minBS.getBytes(), 0, minBS.getLength()); |
| |
| ByteArrayOutputStream endOS = new ByteArrayOutputStream(); |
| endOS.write(0);// add a leading zero so bigint does not think its negative |
| endOS.write(maxBS.getBytes(), 0, maxBS.getLength()); |
| |
| // make the numbers of the same magnitude |
| if (startOS.size() < endOS.size()) |
| appendZeros(startOS, endOS.size() - startOS.size()); |
| else if (endOS.size() < startOS.size()) |
| appendZeros(endOS, startOS.size() - endOS.size()); |
| |
| BigInteger min = new BigInteger(startOS.toByteArray()); |
| BigInteger max = new BigInteger(endOS.toByteArray()); |
| |
| BigInteger mid = max.subtract(min).divide(BigInteger.valueOf(2)).add(min); |
| |
| byte[] ba = mid.toByteArray(); |
| |
| Text ret = new Text(); |
| |
| if (ba.length == startOS.size()) { |
| if (ba[0] != 0) |
| throw new RuntimeException(); |
| |
| // big int added a zero so it would not be negative, drop it |
| ret.set(ba, 1, ba.length - 1); |
| } else { |
| int expLen = Math.max(minBS.getLength(), maxBS.getLength()); |
| // big int will drop leading 0x0 bytes |
| for (int i = ba.length; i < expLen; i++) { |
| ret.append(new byte[] {0}, 0, 1); |
| } |
| |
| ret.append(ba, 0, ba.length); |
| } |
| |
| // remove trailing 0x0 bytes |
| while (ret.getLength() > 0 && ret.getBytes()[ret.getLength() - 1] == 0 |
| && ret.compareTo(minBS) > 0) { |
| Text t = new Text(); |
| t.set(ret.getBytes(), 0, ret.getLength() - 1); |
| ret = t; |
| } |
| |
| return ret; |
| } |
| |
| private static Text _findMax(Scanner scanner, Text start, boolean inclStart, Text end, |
| boolean inclEnd) { |
| |
| // System.out.printf("findMax(%s, %s, %s, %s)%n", Key.toPrintableString(start.getBytes(), 0, |
| // start.getLength(), 1000), inclStart, |
| // Key.toPrintableString(end.getBytes(), 0, end.getLength(), 1000), inclEnd); |
| |
| int cmp = start.compareTo(end); |
| |
| if (cmp >= 0) { |
| if (inclStart && inclEnd && cmp == 0) { |
| scanner.setRange(new Range(start, true, end, true)); |
| Iterator<Entry<Key,Value>> iter = scanner.iterator(); |
| if (iter.hasNext()) |
| return iter.next().getKey().getRow(); |
| } |
| |
| return null; |
| } |
| |
| Text mid = findMidPoint(start, end); |
| // System.out.println("mid = :"+Key.toPrintableString(mid.getBytes(), 0, mid.getLength(), |
| // 1000)+":"); |
| |
| scanner.setRange(new Range(mid, mid.equals(start) ? inclStart : true, end, inclEnd)); |
| |
| Iterator<Entry<Key,Value>> iter = scanner.iterator(); |
| |
| if (iter.hasNext()) { |
| Key next = iter.next().getKey(); |
| |
| int count = 0; |
| while (count < 10 && iter.hasNext()) { |
| next = iter.next().getKey(); |
| count++; |
| } |
| |
| if (!iter.hasNext()) |
| return next.getRow(); |
| |
| Text ret = _findMax(scanner, next.followingKey(PartialKey.ROW).getRow(), true, end, inclEnd); |
| if (ret == null) |
| return next.getRow(); |
| else |
| return ret; |
| } else { |
| |
| return _findMax(scanner, start, inclStart, mid, mid.equals(start) ? inclStart : false); |
| } |
| } |
| |
| private static Text findInitialEnd(Scanner scanner) { |
| Text end = new Text(new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}); |
| |
| scanner.setRange(new Range(end, null)); |
| |
| while (scanner.iterator().hasNext()) { |
| Text t = new Text(); |
| t.append(end.getBytes(), 0, end.getLength()); |
| t.append(end.getBytes(), 0, end.getLength()); |
| end = t; |
| scanner.setRange(new Range(end, null)); |
| } |
| |
| return end; |
| } |
| |
| public static Text findMax(Scanner scanner, Text start, boolean is, Text end, boolean ie) |
| throws TableNotFoundException { |
| |
| scanner.setBatchSize(12); |
| IteratorSetting cfg = new IteratorSetting(Integer.MAX_VALUE, SortedKeyIterator.class); |
| scanner.addScanIterator(cfg); |
| |
| if (start == null) { |
| start = new Text(); |
| is = true; |
| } |
| |
| if (end == null) |
| end = findInitialEnd(scanner); |
| |
| return _findMax(scanner, start, is, end, ie); |
| } |
| } |