Java tutorial
/** * 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.cloudata.core.client.scanner; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.cloudata.core.client.CellFilter; import org.cloudata.core.client.CTable; import org.cloudata.core.client.CTableManager; import org.cloudata.core.client.Row; import org.cloudata.core.client.RowFilter; import org.cloudata.core.client.ScanCell; import org.cloudata.core.common.Constants; import org.cloudata.core.common.conf.CloudataConf; import org.cloudata.core.common.io.CWritableUtils; import org.cloudata.core.common.util.NetworkUtil; import org.cloudata.core.tablet.ColumnValue; import org.cloudata.core.tablet.TabletInfo; import org.cloudata.core.tabletserver.DataServiceProtocol; /** * get ? ? ?? ?? ? ?. * ? get rowkey ? ? . * rowkey ?? ?? ? Scanner ?. Scanner open? close? TabletServer ? * ? ?? ?? . * (? ? next ? ? ? ?? scanner close ) * SingleTableScanner ???? Scanner? Scanner ? Tablet, ? Column? Scan? . * startRowKey scan? ? endRowKey ? Tablet? scan. * Command Line ??? ? .(: bin/cloudata org.cloudata.core.client.SingleTabletScanner <table name> <tablet name>) * @see MultiTabletScanner SingleTabletMultipleColumnScanner MultipleColumnScanner * @author * */ class SingleTabletScanner extends AbstractTableScanner { private static final Log LOG = LogFactory.getLog(SingleTabletScanner.class.getName()); private Socket socket = null; private int READ_TIMEOUT = 60 * 1000; private DataInputStream in; private boolean end = false; protected TabletInfo tabletInfo; private ColumnValue[] preFetchedResults; private int prefetchIndex = 0; private RowFilter rowFilter; private Thread touchThread; private AtomicLong lastNextTime = new AtomicLong(); private ColumnValue lastColumnValue; private boolean timeoutException = false; protected SingleTabletScanner(final CloudataConf conf, final TabletInfo tabletInfo, final RowFilter rowFilter) throws IOException { this.tabletInfo = tabletInfo; //ScanFilter ? column? . if (rowFilter.getCellFilters().size() == 0) { throw new IOException("No column in RowFilter"); } this.rowFilter = rowFilter; this.columnName = rowFilter.getColumns()[0]; String hostName = tabletInfo.getAssignedHostName(); int index = hostName.indexOf(":"); String host = hostName.substring(0, index); InetSocketAddress targetAddr = null; try { DataServiceProtocol tabletServer = CTableManager.connectTabletServer(hostName, conf); String port = tabletServer.getTabletServerConf("tabletServer.scanner.port"); targetAddr = NetworkUtil.getAddress(host + ":" + port); } catch (IOException e) { LOG.error("Can't connect to " + hostName + "," + e.getMessage()); throw e; } try { socket = new Socket(); socket.connect(targetAddr, READ_TIMEOUT); socket.setSoTimeout(READ_TIMEOUT); DataOutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); out.write(Constants.OPEN_SCANNER); CWritableUtils.writeString(out, tabletInfo.getTabletName()); CWritableUtils.writeString(out, columnName); rowFilter.write(out); out.flush(); in = new DataInputStream(new BufferedInputStream(socket.getInputStream())); byte successOpen = (byte) in.read(); if (successOpen == Constants.SCANNER_OPEN_FAIL) { String errorMessage = CWritableUtils.readString(in); in.close(); throw new IOException(errorMessage); } String scannerId = CWritableUtils.readString(in); touchThread = new Thread(new LeaseTouchThread(conf, tabletInfo.getAssignedHostName(), scannerId)); touchThread.setName( "ScannerLeaseTouchThread_" + tabletInfo.getTabletName() + "_" + System.currentTimeMillis()); touchThread.start(); } catch (SocketException e) { this.close(); //LOG.warn("Scan open error cause:" + e.getMessage() + ", tablet=" + tabletInfo); throw e; } catch (IOException e) { this.close(); //LOG.warn("Scan open error cause:" + e.getMessage() + ", tablet=" + tabletInfo, e); throw e; } catch (Exception e) { //LOG.warn("Scan open error cause:" + e.getMessage() + ", tablet=" + tabletInfo, e); throw new IOException(e.getMessage(), e); } } void touch() { } public ScanCell next() throws IOException { if (timeoutException) { throw new IOException("Scanner Touch Thread stoped cause next() calling is so dealyed(120sec)"); } if (end) { if (touchThread.isAlive()) { touchThread.interrupt(); } return null; } lastNextTime.getAndSet(System.currentTimeMillis()); if (preFetchedResults != null && preFetchedResults.length > prefetchIndex) { ColumnValue result = preFetchedResults[prefetchIndex]; prefetchIndex++; lastColumnValue = result; //System.out.println(lastColumnValue.getRowKey().toString()); return lastColumnValue.copyToScanCell(columnName); } int size = -1; try { size = in.readInt(); //System.out.println("Size:" + size); } catch (IOException e) { if (lastColumnValue != null) { LOG.debug("lastColumnValue:" + lastColumnValue + "," + tabletInfo.getTabletName()); } in.close(); if (touchThread.isAlive()) { touchThread.interrupt(); } LOG.error("Scan Error:" + tabletInfo); throw e; } if (size == -1) { end = true; if (touchThread.isAlive()) { touchThread.interrupt(); } return null; } if (size == 0) { if (touchThread.isAlive()) { touchThread.interrupt(); } return null; } preFetchedResults = new ColumnValue[size]; //int count = 0; for (int i = 0; i < size; i++) { preFetchedResults[i] = new ColumnValue(); preFetchedResults[i].readFields(in); //count++; } //System.out.println("Count:" + count); prefetchIndex = 1; lastColumnValue = preFetchedResults[0]; return preFetchedResults[0].copyToScanCell(columnName); } protected boolean isEnd() { return end; } protected void setEnd(boolean end) { this.end = end; } public void close() throws IOException { if (in != null) { in.close(); } if (socket != null) { socket.close(); } if (touchThread != null) { touchThread.interrupt(); } } public boolean equals(Object obj) { if (!(obj instanceof SingleTabletScanner)) { return false; } SingleTabletScanner scanner = (SingleTabletScanner) obj; return tabletInfo.equals(scanner.tabletInfo); } class LeaseTouchThread implements Runnable { String leaseId; CloudataConf conf; String hostName; public LeaseTouchThread(CloudataConf conf, String hostName, String leaseId) { this.leaseId = leaseId; this.conf = conf; this.hostName = hostName; } public void run() { try { try { Thread.sleep(5 * 1000); } catch (InterruptedException e) { //System.out.println(touchThread.getName() + "\tEnd1"); return; } int retry = 0; DataServiceProtocol tabletServer = null; while (true) { try { tabletServer = CTableManager.connectTabletServer(hostName, conf); break; } catch (Exception e) { retry++; if (retry >= 5) { LOG.error("Scanner Touch Open Error:Can't connectTabletServer:" + hostName + "," + tabletInfo, e); } try { Thread.sleep(3 * 1000); } catch (InterruptedException err) { return; } } } while (true) { try { tabletServer.touch(leaseId); } catch (Exception e) { LOG.error("Scanner Touch Error:" + hostName + "," + e.getMessage()); } try { Thread.sleep(10 * 1000); } catch (InterruptedException e) { //System.out.println(touchThread.getName() + "\tEnd2"); return; } //next call? ? ? warn . //next call? ? ? ? ? close() ? ? //? LeaseTouchThread ? ? ? ?? ? . //? warn? ? ? ?? close() ?? ?. if (System.currentTimeMillis() - lastNextTime.get() > 120 * 1000) { LOG.warn("not called scanner.next() for 120sec after last calling. " + "please check scanner.close() explicitly in your program." + "tabletName=" + tabletInfo.getTabletName() + ",columnName=" + columnName); lastNextTime.getAndSet(System.currentTimeMillis()); } } } catch (Exception e) { LOG.error("Scanner Touch Open Error:" + hostName + "," + tabletInfo, e); } } } @Override public String[] getColumnNames() { return new String[] { columnName }; } public static void main(String[] args) throws Exception { if (args.length < 3) { System.out.println("Usgae java SingleTabletScanner <table name> <tablet name> <col name>"); System.exit(0); } CTable ctable = CTable.openTable(new CloudataConf(), args[0]); TabletInfo tabletInfo = ctable.getTabletInfo(args[1]); if (tabletInfo == null) { System.exit(0); System.out.println("No Tablet:" + args[1]); } else { System.out.println("Tablet:" + tabletInfo); } RowFilter rowFilter = new RowFilter(); rowFilter.addCellFilter(new CellFilter(args[2])); SingleTabletScanner scanner = new SingleTabletScanner(ctable.getConf(), tabletInfo, rowFilter); Row row = null; while ((row = scanner.nextRow()) != null) { System.out.println("scanCell:" + row.getKey()); } } }