diff --git a/CHANGES.txt b/CHANGES.txt index aa2f3645912..83620520fdd 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,980 +1,982 @@ -Hbase Change Log - -Release 0.3.0 - Unreleased - - INCOMPATIBLE CHANGES - BUG FIXES - HBASE-805 Remove unnecessary getRow overloads in HRS (Jonathan Gray via - Jim Kellerman) (Fix whitespace diffs in HRegionServer) - HBASE-811 HTD is not fully copyable (Andrew Purtell via Jim Kellerman) - HBASE-729 Client region/metadata cache should have a public method for - invalidating entries (Andrew Purtell via Stack) - - IMPROVEMENTS - HBASE-801 When a table haven't disable, shell could response in a "user - friendly" way. - HBASE-816 TableMap should survive USE (Andrew Purtell via Stack) - - NEW FEATURES - OPTIMIZATIONS - -Release 0.2.0 - August 8, 2008. - - INCOMPATIBLE CHANGES - HBASE-584 Names in the filter interface are confusing (Clint Morgan via - Jim Kellerman) (API change for filters) - HBASE-601 Just remove deprecated methods in HTable; 0.2 is not backward - compatible anyways - HBASE-82 Row keys should be array of bytes - HBASE-76 Purge servers of Text (Done as part of HBASE-82 commit). - HBASE-487 Replace hql w/ a hbase-friendly jirb or jython shell - Part 1: purge of hql and added raw jirb in its place. - HBASE-521 Improve client scanner interface - HBASE-288 Add in-memory caching of data. Required update of hadoop to - 0.17.0-dev.2008-02-07_12-01-58. (Tom White via Stack) - HBASE-696 Make bloomfilter true/false and self-sizing - HBASE-720 clean up inconsistencies around deletes (Izaak Rubin via Stack) - HBASE-796 Deprecates Text methods from HTable - (Michael Gottesman via Stack) - - BUG FIXES - HBASE-574 HBase does not load hadoop native libs (Rong-En Fan via Stack) - HBASE-598 Loggging, no .log file; all goes into .out - HBASE-622 Remove StaticTestEnvironment and put a log4j.properties in src/test - HBASE-624 Master will shut down if number of active region servers is zero - even if shutdown was not requested - HBASE-629 Split reports incorrect elapsed time - HBASE-623 Migration script for hbase-82 - HBASE-630 Default hbase.rootdir is garbage - HBASE-589 Remove references to deprecated methods in Hadoop once - hadoop-0.17.0 is released - HBASE-638 Purge \r from src - HBASE-644 DroppedSnapshotException but RegionServer doesn't restart - HBASE-641 Improve master split logging - HBASE-642 Splitting log in a hostile environment -- bad hdfs -- we drop - write-ahead-log edits - HBASE-646 EOFException opening HStoreFile info file (spin on HBASE-645and 550) - HBASE-648 If mapfile index is empty, run repair - HBASE-640 TestMigrate failing on hudson - HBASE-651 Table.commit should throw NoSuchColumnFamilyException if column - family doesn't exist - HBASE-649 API polluted with default and protected access data members and methods - HBASE-650 Add String versions of get, scanner, put in HTable - HBASE-656 Do not retry exceptions such as unknown scanner or illegal argument - HBASE-659 HLog#cacheFlushLock not cleared; hangs a region - HBASE-663 Incorrect sequence number for cache flush - HBASE-655 Need programmatic way to add column family: need programmatic way - to enable/disable table - HBASE-654 API HTable.getMetadata().addFamily shouldn't be exposed to user - HBASE-666 UnmodifyableHRegionInfo gives the wrong encoded name - HBASE-668 HBASE-533 broke build - HBASE-670 Historian deadlocks if regionserver is at global memory boundary - and is hosting .META. - HBASE-665 Server side scanner doesn't honor stop row - HBASE-662 UI in table.jsp gives META locations, not the table's regions - location (Jean-Daniel Cryans via Stack) - HBASE-676 Bytes.getInt returns a long (Clint Morgan via Stack) - HBASE-680 Config parameter hbase.io.index.interval should be - hbase.index.interval, according to HBaseMapFile.HbaseWriter - (LN via Stack) - HBASE-682 Unnecessary iteration in HMemcache.internalGet? got much better - reading performance after break it (LN via Stack) - HBASE-686 MemcacheScanner didn't return the first row(if it exists), - because HScannerInterface's output incorrect (LN via Jim Kellerman) - HBASE-691 get* and getScanner are different in how they treat column parameter - HBASE-694 HStore.rowAtOrBeforeFromMapFile() fails to locate the row if # of mapfiles >= 2 - (Rong-En Fan via Bryan) - HBASE-652 dropping table fails silently if table isn't disabled - HBASE-683 can not get svn revision # at build time if locale is not english - (Rong-En Fan via Stack) - HBASE-699 Fix TestMigrate up on Hudson - HBASE-615 Region balancer oscillates during cluster startup - HBASE-613 Timestamp-anchored scanning fails to find all records - HBASE-681 NPE in Memcache - HBASE-701 Showing bytes in log when should be String - HBASE-702 deleteall doesn't - HBASE-704 update new shell docs and commands on help menu - HBASE-709 Deadlock while rolling WAL-log while finishing flush - HBASE-710 If clocks are way off, then we can have daughter split come - before rather than after its parent in .META. - HBASE-714 Showing bytes in log when should be string (2) - HBASE-627 Disable table doesn't work reliably - HBASE-716 TestGet2.testGetClosestBefore fails with hadoop-0.17.1 - HBASE-715 Base HBase 0.2 on Hadoop 0.17.1 - HBASE-718 hbase shell help info - HBASE-717 alter table broke with new shell returns InvalidColumnNameException - HBASE-573 HBase does not read hadoop-*.xml for dfs configuration after - moving out hadoop/contrib - HBASE-11 Unexpected exits corrupt DFS - HBASE-12 When hbase regionserver restarts, it says "impossible state for - createLease()" - HBASE-575 master dies with stack overflow error if rootdir isn't qualified - HBASE-582 HBase 554 forgot to clear results on each iteration caused by a filter - (Clint Morgan via Stack) - HBASE-532 Odd interaction between HRegion.get, HRegion.deleteAll and compactions - HBASE-10 HRegionServer hangs upon exit due to DFSClient Exception - HBASE-595 RowFilterInterface.rowProcessed() is called *before* fhe final - filtering decision is made (Clint Morgan via Stack) - HBASE-586 HRegion runs HStore memcache snapshotting -- fix it so only HStore - knows about workings of memcache - HBASE-588 Still a 'hole' in scanners, even after HBASE-532 - HBASE-604 Don't allow CLASSPATH from environment pollute the hbase CLASSPATH - HBASE-608 HRegionServer::getThisIP() checks hadoop config var for dns interface name - (Jim R. Wilson via Stack) - HBASE-609 Master doesn't see regionserver edits because of clock skew - HBASE-607 MultiRegionTable.makeMultiRegionTable is not deterministic enough - for regression tests - HBASE-405 TIF and TOF use log4j directly rather than apache commons-logging - HBASE-618 We always compact if 2 files, regardless of the compaction threshold setting - HBASE-619 Fix 'logs' link in UI - HBASE-478 offlining of table does not run reliably - HBASE-453 undeclared throwable exception from HTable.get - HBASE-620 testmergetool failing in branch and trunk since hbase-618 went in - HBASE-550 EOF trying to read reconstruction log stops region deployment - HBASE-551 Master stuck splitting server logs in shutdown loop; on each - iteration, edits are aggregated up into the millions - HBASE-505 Region assignments should never time out so long as the region - server reports that it is processing the open request - HBASE-561 HBase package does not include LICENSE.txt nor build.xml - HBASE-563 TestRowFilterAfterWrite erroneously sets master address to - 0.0.0.0:60100 rather than relying on conf - HBASE-507 Use Callable pattern to sleep between retries - HBASE-564 Don't do a cache flush if there are zero entries in the cache. - HBASE-554 filters generate StackOverflowException - HBASE-567 Reused BatchUpdate instances accumulate BatchOperations - HBASE-577 NPE getting scanner - HBASE-19 CountingBloomFilter can overflow its storage - (Stu Hood and Bryan Duxbury via Stack) - HBASE-28 thrift put/mutateRow methods need to throw IllegalArgument - exceptions (Dave Simpson via Bryan Duxbury via Stack) - HBASE-2 hlog numbers should wrap around when they reach 999 - (Bryan Duxbury via Stack) - HBASE-421 TestRegionServerExit broken - HBASE-426 hbase can't find remote filesystem - HBASE-437 Clear Command should use system.out (Edward Yoon via Stack) - HBASE-434, HBASE-435 TestTableIndex and TestTableMapReduce failed in Hudson builds - HBASE-446 Fully qualified hbase.rootdir doesn't work - HBASE-438 XMLOutputter state should be initialized. (Edward Yoon via Stack) - HBASE-8 Delete table does not remove the table directory in the FS - HBASE-428 Under continuous upload of rows, WrongRegionExceptions are thrown - that reach the client even after retries - HBASE-460 TestMigrate broken when HBase moved to subproject - HBASE-462 Update migration tool - HBASE-473 When a table is deleted, master sends multiple close messages to - the region server - HBASE-490 Doubly-assigned .META.; master uses one and clients another - HBASE-492 hbase TRUNK does not build against hadoop TRUNK - HBASE-496 impossible state for createLease writes 400k lines in about 15mins - HBASE-472 Passing on edits, we dump all to log - HBASE-495 No server address listed in .META. - HBASE-433 HBASE-251 Region server should delete restore log after successful - restore, Stuck replaying the edits of crashed machine. - HBASE-27 hregioninfo cell empty in meta table - HBASE-501 Empty region server address in info:server entry and a - startcode of -1 in .META. - HBASE-516 HStoreFile.finalKey does not update the final key if it is not - the top region of a split region - HBASE-525 HTable.getRow(Text) does not work (Clint Morgan via Bryan Duxbury) - HBASE-524 Problems with getFull - HBASE-528 table 'does not exist' when it does - HBASE-531 Merge tool won't merge two overlapping regions (port HBASE-483 to - trunk) - HBASE-537 Wait for hdfs to exit safe mode - HBASE-476 RegexpRowFilter behaves incorectly when there are multiple store - files (Clint Morgan via Jim Kellerman) - HBASE-527 RegexpRowFilter does not work when there are columns from - multiple families (Clint Morgan via Jim Kellerman) - HBASE-534 Double-assignment at SPLIT-time - HBASE-712 midKey found compacting is the first, not necessarily the optimal - HBASE-719 Find out why users have network problems in HBase and not in Hadoop - and HConnectionManager (Jean-Daniel Cryans via Stack) - HBASE-703 Invalid regions listed by regionserver.jsp (Izaak Rubin via Stack) - HBASE-674 Memcache size unreliable - HBASE-726 Unit tests won't run because of a typo (Sebastien Rainville via Stack) - HBASE-727 Client caught in an infinite loop when trying to connect to cached - server locations (Izaak Rubin via Stack) - HBASE-732 shell formatting error with the describe command - (Izaak Rubin via Stack) - HBASE-731 delete, deletefc in HBase shell do not work correctly - (Izaak Rubin via Stack) - HBASE-734 scan '.META.', {LIMIT => 10} crashes (Izaak Rubin via Stack) - HBASE-736 Should have HTable.deleteAll(String row) and HTable.deleteAll(Text row) - (Jean-Daniel Cryans via Stack) - HBASE-740 ThriftServer getting table names incorrectly (Tim Sell via Stack) - HBASE-742 Rename getMetainfo in HTable as getTableDescriptor - HBASE-739 HBaseAdmin.createTable() using old HTableDescription doesn't work - (Izaak Rubin via Stack) - HBASE-744 BloomFilter serialization/deserialization broken - HBASE-742 Column length limit is not enforced (Jean-Daniel Cryans via Stack) - HBASE-737 Scanner: every cell in a row has the same timestamp - HBASE-700 hbase.io.index.interval need be configuratable in column family - (Andrew Purtell via Stack) - HBASE-62 Allow user add arbitrary key/value pairs to table and column - descriptors (Andrew Purtell via Stack) - HBASE-34 Set memcache flush size per column (Andrew Purtell via Stack) - HBASE-42 Set region split size on table creation (Andrew Purtell via Stack) - HBASE-43 Add a read-only attribute to columns (Andrew Purtell via Stack) - HBASE-424 Should be able to enable/disable .META. table - HBASE-679 Regionserver addresses are still not right in the new tables page - HBASE-758 Throwing IOE read-only when should be throwing NSRE - HBASE-743 bin/hbase migrate upgrade fails when redo logs exists - HBASE-754 The JRuby shell documentation is wrong in "get" and "put" - (Jean-Daniel Cryans via Stack) - HBASE-756 In HBase shell, the put command doesn't process the timestamp - (Jean-Daniel Cryans via Stack) - HBASE-757 REST mangles table names (Sishen via Stack) - HBASE-706 On OOME, regionserver sticks around and doesn't go down with cluster - (Jean-Daniel Cryans via Stack) - HBASE-759 TestMetaUtils failing on hudson - HBASE-761 IOE: Stream closed exception all over logs - HBASE-763 ClassCastException from RowResult.get(String) - (Andrew Purtell via Stack) - HBASE-764 The name of column request has padding zero using REST interface - (Sishen Freecity via Stack) - HBASE-750 NPE caused by StoreFileScanner.updateReaders - HBASE-769 TestMasterAdmin fails throwing RegionOfflineException when we're - expecting IllegalStateException - HBASE-766 FileNotFoundException trying to load HStoreFile 'data' - HBASE-770 Update HBaseRPC to match hadoop 0.17 RPC - HBASE-780 Can't scan '.META.' from new shell - HBASE-424 Should be able to enable/disable .META. table - HBASE-771 Names legal in 0.1 are not in 0.2; breaks migration - HBASE-788 Div by zero in Master.jsp (Clint Morgan via Jim Kellerman) - HBASE-791 RowCount doesn't work (Jean-Daniel Cryans via Stack) - HBASE-751 dfs exception and regionserver stuck during heavy write load - HBASE-793 HTable.getStartKeys() ignores table names when matching columns - (Andrew Purtell and Dru Jensen via Stack) - HBASE-790 During import, single region blocks requests for >10 minutes, - thread dumps, throws out pending requests, and continues - (Jonathan Gray via Stack) - - IMPROVEMENTS - HBASE-559 MR example job to count table rows - HBASE-596 DemoClient.py (Ivan Begtin via Stack) - HBASE-581 Allow adding filters to TableInputFormat (At same time, ensure TIF - is subclassable) (David Alves via Stack) - HBASE-603 When an exception bubbles out of getRegionServerWithRetries, wrap - the exception with a RetriesExhaustedException - HBASE-600 Filters have excessive DEBUG logging - HBASE-611 regionserver should do basic health check before reporting - alls-well to the master - HBASE-614 Retiring regions is not used; exploit or remove - HBASE-538 Improve exceptions that come out on client-side - HBASE-569 DemoClient.php (Jim R. Wilson via Stack) - HBASE-522 Where new Text(string) might be used in client side method calls, - add an overload that takes String (Done as part of HBASE-82) - HBASE-570 Remove HQL unit test (Done as part of HBASE-82 commit). - HBASE-626 Use Visitor pattern in MetaRegion to reduce code clones in HTable - and HConnectionManager (Jean-Daniel Cryans via Stack) - HBASE-621 Make MAX_VERSIONS work like TTL: In scans and gets, check - MAX_VERSIONs setting and return that many only rather than wait on - compaction (Jean-Daniel Cryans via Stack) - HBASE-504 Allow HMsg's carry a payload: e.g. exception that happened over - on the remote side. - HBASE-583 RangeRowFilter/ColumnValueFilter to allow choice of rows based on - a (lexicographic) comparison to column's values - (Clint Morgan via Stack) - HBASE-579 Add hadoop 0.17.x - HBASE-660 [Migration] addColumn/deleteColumn functionality in MetaUtils - HBASE-632 HTable.getMetadata is very inefficient - HBASE-671 New UI page displaying all regions in a table should be sorted - HBASE-672 Sort regions in the regionserver UI - HBASE-677 Make HTable, HRegion, HRegionServer, HStore, and HColumnDescriptor - subclassable (Clint Morgan via Stack) - HBASE-682 Regularize toString - HBASE-672 Sort regions in the regionserver UI - HBASE-469 Streamline HStore startup and compactions - HBASE-544 Purge startUpdate from internal code and test cases - HBASE-557 HTable.getRow() should receive RowResult objects - HBASE-452 "region offline" should throw IOException, not IllegalStateException - HBASE-541 Update hadoop jars. - HBASE-523 package-level javadoc should have example client - HBASE-415 Rewrite leases to use DelayedBlockingQueue instead of polling - HBASE-35 Make BatchUpdate public in the API - HBASE-409 Add build path to svn:ignore list (Edward Yoon via Stack) - HBASE-408 Add .classpath and .project to svn:ignore list - (Edward Yoon via Stack) - HBASE-410 Speed up the test suite (make test timeout 5 instead of 15 mins). - HBASE-281 Shell should allow deletions in .META. and -ROOT- tables - (Edward Yoon & Bryan Duxbury via Stack) - HBASE-56 Unnecessary HQLClient Object creation in a shell loop - (Edward Yoon via Stack) - HBASE-3 rest server: configure number of threads for jetty - (Bryan Duxbury via Stack) - HBASE-416 Add apache-style logging to REST server and add setting log - level, etc. - HBASE-406 Remove HTable and HConnection close methods - (Bryan Duxbury via Stack) - HBASE-418 Move HMaster and related classes into master package - (Bryan Duxbury via Stack) - HBASE-410 Speed up the test suite - Apparently test timeout was too - aggressive for Hudson. TestLogRolling timed out even though it - was operating properly. Change test timeout to 10 minutes. - HBASE-436 website: http://hadoop.apache.org/hbase - HBASE-417 Factor TableOperation and subclasses into separate files from - HMaster (Bryan Duxbury via Stack) - HBASE-440 Add optional log roll interval so that log files are garbage - collected - HBASE-407 Keep HRegionLocation information in LRU structure - HBASE-444 hbase is very slow at determining table is not present - HBASE-438 XMLOutputter state should be initialized. - HBASE-414 Move client classes into client package - HBASE-79 When HBase needs to be migrated, it should display a message on - stdout, not just in the logs - HBASE-461 Simplify leases. - HBASE-419 Move RegionServer and related classes into regionserver package - HBASE-457 Factor Master into Master, RegionManager, and ServerManager - HBASE-464 HBASE-419 introduced javadoc errors - HBASE-468 Move HStoreKey back to o.a.h.h - HBASE-442 Move internal classes out of HRegionServer - HBASE-466 Move HMasterInterface, HRegionInterface, and - HMasterRegionInterface into o.a.h.h.ipc - HBASE-479 Speed up TestLogRolling - HBASE-480 Tool to manually merge two regions - HBASE-477 Add support for an HBASE_CLASSPATH - HBASE-443 Move internal classes out of HStore - HBASE-515 At least double default timeouts between regionserver and master - HBASE-529 RegionServer needs to recover if datanode goes down - HBASE-456 Clearly state which ports need to be opened in order to run HBase - HBASE-536 Remove MiniDFS startup from MiniHBaseCluster - HBASE-521 Improve client scanner interface - HBASE-562 Move Exceptions to subpackages (Jean-Daniel Cryans via Stack) - HBASE-631 HTable.getRow() for only a column family - (Jean-Daniel Cryans via Stack) - HBASE-731 Add a meta refresh tag to the Web ui for master and region server - (Jean-Daniel Cryans via Stack) - HBASE-735 hbase shell doesn't trap CTRL-C signal (Jean-Daniel Cryans via Stack) - HBASE-730 On startup, rinse STARTCODE and SERVER from .META. - (Jean-Daniel Cryans via Stack) - HBASE-738 overview.html in need of updating (Izaak Rubin via Stack) - HBASE-745 scaling of one regionserver, improving memory and cpu usage (partial) - (LN via Stack) - HBASE-746 Batching row mutations via thrift (Tim Sell via Stack) - HBASE-772 Up default lease period from 60 to 120 seconds - HBASE-779 Test changing hbase.hregion.memcache.block.multiplier to 2 - HBASE-783 For single row, single family retrieval, getRow() works half - as fast as getScanner().next() (Jean-Daniel Cryans via Stack) - HBASE-789 add clover coverage report targets (Rong-en Fan via Stack) - - NEW FEATURES - HBASE-47 Option to set TTL for columns in hbase - (Andrew Purtell via Bryan Duxbury and Stack) - HBASE-23 UI listing regions should be sorted by address and show additional - region state (Jean-Daniel Cryans via Stack) - HBASE-639 Add HBaseAdmin.getTableDescriptor function - HBASE-533 Region Historian - HBASE-487 Replace hql w/ a hbase-friendly jirb or jython shell - HBASE-548 Tool to online single region - HBASE-71 Master should rebalance region assignments periodically - HBASE-512 Add configuration for global aggregate memcache size - HBASE-40 Add a method of getting multiple (but not all) cells for a row - at once - HBASE-506 When an exception has to escape ServerCallable due to exhausted - retries, show all the exceptions that lead to this situation - HBASE-747 Add a simple way to do batch updates of many rows (Jean-Daniel - Cryans via JimK) - HBASE-733 Enhance Cell so that it can contain multiple values at multiple - timestamps - HBASE-511 Do exponential backoff in clients on NSRE, WRE, ISE, etc. - (Andrew Purtell via Jim Kellerman) - - OPTIMIZATIONS - HBASE-430 Performance: Scanners and getRow return maps with duplicate data - -Release 0.1.3 - 07/25/2008 - - BUG FIXES - HBASE-644 DroppedSnapshotException but RegionServer doesn't restart - HBASE-645 EOFException opening region (HBASE-550 redux) - HBASE-641 Improve master split logging - HBASE-642 Splitting log in a hostile environment -- bad hdfs -- we drop - write-ahead-log edits - HBASE-646 EOFException opening HStoreFile info file (spin on HBASE-645 and 550) - HBASE-648 If mapfile index is empty, run repair - HBASE-659 HLog#cacheFlushLock not cleared; hangs a region - HBASE-663 Incorrect sequence number for cache flush - HBASE-652 Dropping table fails silently if table isn't disabled - HBASE-674 Memcache size unreliable - HBASE-665 server side scanner doesn't honor stop row - HBASE-681 NPE in Memcache (Clint Morgan via Jim Kellerman) - HBASE-680 config parameter hbase.io.index.interval should be - hbase.index.interval, accroding to HBaseMapFile.HbaseWriter - (LN via Stack) - HBASE-684 unnecessary iteration in HMemcache.internalGet? got much better - reading performance after break it (LN via Stack) - HBASE-686 MemcacheScanner didn't return the first row(if it exists), - because HScannerInterface's output incorrect (LN via Jim Kellerman) - HBASE-613 Timestamp-anchored scanning fails to find all records - HBASE-709 Deadlock while rolling WAL-log while finishing flush - HBASE-707 High-load import of data into single table/family never triggers split - HBASE-710 If clocks are way off, then we can have daughter split come - before rather than after its parent in .META. - -Release 0.1.2 - 05/13/2008 - - BUG FIXES - HBASE-577 NPE getting scanner - HBASE-574 HBase does not load hadoop native libs (Rong-En Fan via Stack). - HBASE-11 Unexpected exits corrupt DFS - best we can do until we have at - least a subset of HADOOP-1700 - HBASE-573 HBase does not read hadoop-*.xml for dfs configuration after - moving out hadoop/contrib - HBASE-12 when hbase regionserver restarts, it says "impossible state for - createLease()" - HBASE-575 master dies with stack overflow error if rootdir isn't qualified - HBASE-500 Regionserver stuck on exit - HBASE-582 HBase 554 forgot to clear results on each iteration caused by a filter - (Clint Morgan via Stack) - HBASE-532 Odd interaction between HRegion.get, HRegion.deleteAll and compactions - HBASE-590 HBase migration tool does not get correct FileSystem or root - directory if configuration is not correct - HBASE-595 RowFilterInterface.rowProcessed() is called *before* fhe final - filtering decision is made (Clint Morgan via Stack) - HBASE-586 HRegion runs HStore memcache snapshotting -- fix it so only HStore - knows about workings of memcache - HBASE-572 Backport HBASE-512 to 0.1 branch - HBASE-588 Still a 'hole' in scanners, even after HBASE-532 - HBASE-604 Don't allow CLASSPATH from environment pollute the hbase CLASSPATH - HBASE-608 HRegionServer::getThisIP() checks hadoop config var for dns interface name - (Jim R. Wilson via Stack) - HBASE-609 Master doesn't see regionserver edits because of clock skew - HBASE-607 MultiRegionTable.makeMultiRegionTable is not deterministic enough - for regression tests - HBASE-478 offlining of table does not run reliably - HBASE-618 We always compact if 2 files, regardless of the compaction threshold setting - HBASE-619 Fix 'logs' link in UI - HBASE-620 testmergetool failing in branch and trunk since hbase-618 went in - - IMPROVEMENTS - HBASE-559 MR example job to count table rows - HBASE-578 Upgrade branch to 0.16.3 hadoop. - HBASE-596 DemoClient.py (Ivan Begtin via Stack) - - -Release 0.1.1 - 04/11/2008 - - BUG FIXES - HBASE-550 EOF trying to read reconstruction log stops region deployment - HBASE-551 Master stuck splitting server logs in shutdown loop; on each - iteration, edits are aggregated up into the millions - HBASE-505 Region assignments should never time out so long as the region - server reports that it is processing the open request - HBASE-552 Fix bloom filter bugs (Andrzej Bialecki via Jim Kellerman) - HBASE-507 Add sleep between retries - HBASE-555 Only one Worker in HRS; on startup, if assigned tens of regions, - havoc of reassignments because open processing is done in series - HBASE-547 UI shows hadoop version, not hbase version - HBASE-561 HBase package does not include LICENSE.txt nor build.xml - HBASE-556 Add 0.16.2 to hbase branch -- if it works - HBASE-563 TestRowFilterAfterWrite erroneously sets master address to - 0.0.0.0:60100 rather than relying on conf - HBASE-554 filters generate StackOverflowException (Clint Morgan via - Jim Kellerman) - HBASE-567 Reused BatchUpdate instances accumulate BatchOperations - - NEW FEATURES - HBASE-548 Tool to online single region - -Release 0.1.0 - - INCOMPATIBLE CHANGES - HADOOP-2750 Deprecated methods startBatchUpdate, commitBatch, abortBatch, - and renewLease have been removed from HTable (Bryan Duxbury via - Jim Kellerman) - HADOOP-2786 Move hbase out of hadoop core - HBASE-403 Fix build after move of hbase in svn - HBASE-494 Up IPC version on 0.1 branch so we cannot mistakenly connect - with a hbase from 0.16.0 - - NEW FEATURES - HBASE-506 When an exception has to escape ServerCallable due to exhausted retries, - show all the exceptions that lead to this situation - - OPTIMIZATIONS - - BUG FIXES - HADOOP-2731 Under load, regions become extremely large and eventually cause - region servers to become unresponsive - HADOOP-2693 NPE in getClosestRowBefore (Bryan Duxbury & Stack) - HADOOP-2599 Some minor improvements to changes in HADOOP-2443 - (Bryan Duxbury & Stack) - HADOOP-2773 Master marks region offline when it is recovering from a region - server death - HBASE-425 Fix doc. so it accomodates new hbase untethered context - HBase-421 TestRegionServerExit broken - HBASE-426 hbase can't find remote filesystem - HBASE-446 Fully qualified hbase.rootdir doesn't work - HBASE-428 Under continuous upload of rows, WrongRegionExceptions are - thrown that reach the client even after retries - HBASE-490 Doubly-assigned .META.; master uses one and clients another - HBASE-496 impossible state for createLease writes 400k lines in about 15mins - HBASE-472 Passing on edits, we dump all to log - HBASE-79 When HBase needs to be migrated, it should display a message on - stdout, not just in the logs - HBASE-495 No server address listed in .META. - HBASE-433 HBASE-251 Region server should delete restore log after successful - restore, Stuck replaying the edits of crashed machine. - HBASE-27 hregioninfo cell empty in meta table - HBASE-501 Empty region server address in info:server entry and a - startcode of -1 in .META. - HBASE-516 HStoreFile.finalKey does not update the final key if it is not - the top region of a split region - HBASE-524 Problems with getFull - HBASE-514 table 'does not exist' when it does - HBASE-537 Wait for hdfs to exit safe mode - HBASE-534 Double-assignment at SPLIT-time - - IMPROVEMENTS - HADOOP-2555 Refactor the HTable#get and HTable#getRow methods to avoid - repetition of retry-on-failure logic (thanks to Peter Dolan and - Bryan Duxbury) - HBASE-281 Shell should allow deletions in .META. and -ROOT- tables - HBASE-480 Tool to manually merge two regions - HBASE-477 Add support for an HBASE_CLASSPATH - HBASE-515 At least double default timeouts between regionserver and master - HBASE-482 package-level javadoc should have example client or at least - point at the FAQ - HBASE-497 RegionServer needs to recover if datanode goes down - HBASE-456 Clearly state which ports need to be opened in order to run HBase - HBASE-483 Merge tool won't merge two overlapping regions - HBASE-476 RegexpRowFilter behaves incorectly when there are multiple store - files (Clint Morgan via Jim Kellerman) - HBASE-527 RegexpRowFilter does not work when there are columns from - multiple families (Clint Morgan via Jim Kellerman) - -Release 0.16.0 - - 2008/02/04 HBase is now a subproject of Hadoop. The first HBase release as - a subproject will be release 0.1.0 which will be equivalent to - the version of HBase included in Hadoop 0.16.0. In order to - accomplish this, the HBase portion of HBASE-288 (formerly - HADOOP-1398) has been backed out. Once 0.1.0 is frozen (depending - mostly on changes to infrastructure due to becoming a sub project - instead of a contrib project), this patch will re-appear on HBase - trunk. - - INCOMPATIBLE CHANGES - HADOOP-2056 A table with row keys containing colon fails to split regions - HADOOP-2079 Fix generated HLog, HRegion names - HADOOP-2495 Minor performance improvements: Slim-down BatchOperation, etc. - HADOOP-2506 Remove the algebra package - HADOOP-2519 Performance improvements: Customized RPC serialization - HADOOP-2478 Restructure how HBase lays out files in the file system (phase 1) - (test input data) - HADOOP-2478 Restructure how HBase lays out files in the file system (phase 2) - Includes migration tool org.apache.hadoop.hbase.util.Migrate - HADOOP-2558 org.onelab.filter.BloomFilter class uses 8X the memory it should - be using - - NEW FEATURES - HADOOP-2061 Add new Base64 dialects - HADOOP-2084 Add a LocalHBaseCluster - HADOOP-2068 RESTful interface (Bryan Duxbury via Stack) - HADOOP-2316 Run REST servlet outside of master - (Bryan Duxbury & Stack) - HADOOP-1550 No means of deleting a'row' (Bryan Duxbuery via Stack) - HADOOP-2384 Delete all members of a column family on a specific row - (Bryan Duxbury via Stack) - HADOOP-2395 Implement "ALTER TABLE ... CHANGE column" operation - (Bryan Duxbury via Stack) - HADOOP-2240 Truncate for hbase (Edward Yoon via Stack) - HADOOP-2389 Provide multiple language bindings for HBase (Thrift) - (David Simpson via Stack) - - OPTIMIZATIONS - HADOOP-2479 Save on number of Text object creations - HADOOP-2485 Make mapfile index interval configurable (Set default to 32 - instead of 128) - HADOOP-2553 Don't make Long objects calculating hbase type hash codes - HADOOP-2377 Holding open MapFile.Readers is expensive, so use less of them - HADOOP-2407 Keeping MapFile.Reader open is expensive: Part 2 - HADOOP-2533 Performance: Scanning, just creating MapWritable in next - consumes >20% CPU - HADOOP-2443 Keep lazy cache of regions in client rather than an - 'authoritative' list (Bryan Duxbury via Stack) - HADOOP-2600 Performance: HStore.getRowKeyAtOrBefore should use - MapFile.Reader#getClosest (before) - (Bryan Duxbury via Stack) - - BUG FIXES - HADOOP-2059 In tests, exceptions in min dfs shutdown should not fail test - (e.g. nightly #272) - HADOOP-2064 TestSplit assertion and NPE failures (Patch build #952 and #953) - HADOOP-2124 Use of `hostname` does not work on Cygwin in some cases - HADOOP-2083 TestTableIndex failed in #970 and #956 - HADOOP-2109 Fixed race condition in processing server lease timeout. - HADOOP-2137 hql.jsp : The character 0x19 is not valid - HADOOP-2109 Fix another race condition in processing dead servers, - Fix error online meta regions: was using region name and not - startKey as key for map.put. Change TestRegionServerExit to - always kill the region server for the META region. This makes - the test more deterministic and getting META reassigned was - problematic. - HADOOP-2155 Method expecting HBaseConfiguration throws NPE when given Configuration - HADOOP-2156 BufferUnderflowException for un-named HTableDescriptors - HADOOP-2161 getRow() is orders of magnitudes slower than get(), even on rows - with one column (Clint Morgan and Stack) - HADOOP-2040 Hudson hangs AFTER test has finished - HADOOP-2274 Excess synchronization introduced by HADOOP-2139 negatively - impacts performance - HADOOP-2196 Fix how hbase sits in hadoop 'package' product - HADOOP-2276 Address regression caused by HADOOP-2274, fix HADOOP-2173 (When - the master times out a region servers lease, the region server - may not restart) - HADOOP-2253 getRow can return HBASE::DELETEVAL cells - (Bryan Duxbury via Stack) - HADOOP-2295 Fix assigning a region to multiple servers - HADOOP-2234 TableInputFormat erroneously aggregates map values - HADOOP-2308 null regioninfo breaks meta scanner - HADOOP-2304 Abbreviated symbol parsing error of dir path in jar command - (Edward Yoon via Stack) - HADOOP-2320 Committed TestGet2 is managled (breaks build). - HADOOP-2322 getRow(row, TS) client interface not properly connected - HADOOP-2309 ConcurrentModificationException doing get of all region start keys - HADOOP-2321 TestScanner2 does not release resources which sometimes cause the - test to time out - HADOOP-2315 REST servlet doesn't treat / characters in row key correctly - (Bryan Duxbury via Stack) - HADOOP-2332 Meta table data selection in Hbase Shell - (Edward Yoon via Stack) - HADOOP-2347 REST servlet not thread safe but run in a threaded manner - (Bryan Duxbury via Stack) - HADOOP-2365 Result of HashFunction.hash() contains all identical values - HADOOP-2362 Leaking hdfs file handle on region split - HADOOP-2338 Fix NullPointerException in master server. - HADOOP-2380 REST servlet throws NPE when any value node has an empty string - (Bryan Duxbury via Stack) - HADOOP-2350 Scanner api returns null row names, or skips row names if - different column families do not have entries for some rows - HADOOP-2283 AlreadyBeingCreatedException (Was: Stuck replay of failed - regionserver edits) - HADOOP-2392 TestRegionServerExit has new failure mode since HADOOP-2338 - HADOOP-2324 Fix assertion failures in TestTableMapReduce - HADOOP-2396 NPE in HMaster.cancelLease - HADOOP-2397 The only time that a meta scanner should try to recover a log is - when the master is starting - HADOOP-2417 Fix critical shutdown problem introduced by HADOOP-2338 - HADOOP-2418 Fix assertion failures in TestTableMapReduce, TestTableIndex, - and TestTableJoinMapReduce - HADOOP-2414 Fix ArrayIndexOutOfBoundsException in bloom filters. - HADOOP-2430 Master will not shut down if there are no active region servers - HADOOP-2199 Add tools for going from hregion filename to region name in logs - HADOOP-2441 Fix build failures in TestHBaseCluster - HADOOP-2451 End key is incorrectly assigned in many region splits - HADOOP-2455 Error in Help-string of CREATE command (Edward Yoon via Stack) - HADOOP-2465 When split parent regions are cleaned up, not all the columns are - deleted - HADOOP-2468 TestRegionServerExit failed in Hadoop-Nightly #338 - HADOOP-2467 scanner truncates resultset when > 1 column families - HADOOP-2503 REST Insert / Select encoding issue (Bryan Duxbury via Stack) - HADOOP-2505 formatter classes missing apache license - HADOOP-2504 REST servlet method for deleting a scanner was not properly - mapped (Bryan Duxbury via Stack) - HADOOP-2507 REST servlet does not properly base64 row keys and column names - (Bryan Duxbury via Stack) - HADOOP-2530 Missing type in new hbase custom RPC serializer - HADOOP-2490 Failure in nightly #346 (Added debugging of hudson failures). - HADOOP-2558 fixes for build up on hudson (part 1, part 2, part 3, part 4) - HADOOP-2500 Unreadable region kills region servers - HADOOP-2579 Initializing a new HTable object against a nonexistent table - throws a NoServerForRegionException instead of a - TableNotFoundException when a different table has been created - previously (Bryan Duxbury via Stack) - HADOOP-2587 Splits blocked by compactions cause region to be offline for - duration of compaction. - HADOOP-2592 Scanning, a region can let out a row that its not supposed - to have - HADOOP-2493 hbase will split on row when the start and end row is the - same cause data loss (Bryan Duxbury via Stack) - HADOOP-2629 Shell digests garbage without complaint - HADOOP-2619 Compaction errors after a region splits - HADOOP-2621 Memcache flush flushing every 60 secs with out considering - the max memcache size - HADOOP-2584 Web UI displays an IOException instead of the Tables - HADOOP-2650 Remove Writables.clone and use WritableUtils.clone from - hadoop instead - HADOOP-2668 Documentation and improved logging so fact that hbase now - requires migration comes as less of a surprise - HADOOP-2686 Removed tables stick around in .META. - HADOOP-2688 IllegalArgumentException processing a shutdown stops - server going down and results in millions of lines of output - HADOOP-2706 HBase Shell crash - HADOOP-2712 under load, regions won't split - HADOOP-2675 Options not passed to rest/thrift - HADOOP-2722 Prevent unintentional thread exit in region server and master - HADOOP-2718 Copy Constructor HBaseConfiguration(Configuration) will override - hbase configurations if argumant is not an instance of - HBaseConfiguration. - HADOOP-2753 Back out 2718; programmatic config works but hbase*xml conf - is overridden - HADOOP-2718 Copy Constructor HBaseConfiguration(Configuration) will override - hbase configurations if argumant is not an instance of - HBaseConfiguration (Put it back again). - HADOOP-2631 2443 breaks HTable.getStartKeys when there is more than one - table or table you are enumerating isn't the first table - Delete empty file: src/contrib/hbase/src/java/org/apache/hadoop/hbase/mapred/ - TableOutputCollector.java per Nigel Daley - - IMPROVEMENTS - HADOOP-2401 Add convenience put method that takes writable - (Johan Oskarsson via Stack) - HADOOP-2074 Simple switch to enable DEBUG level-logging in hbase - HADOOP-2088 Make hbase runnable in $HADOOP_HOME/build(/contrib/hbase) - HADOOP-2126 Use Bob Jenkins' hash for bloom filters - HADOOP-2157 Make Scanners implement Iterable - HADOOP-2176 Htable.deleteAll documentation is ambiguous - HADOOP-2139 (phase 1) Increase parallelism in region servers. - HADOOP-2267 [Hbase Shell] Change the prompt's title from 'hbase' to 'hql'. - (Edward Yoon via Stack) - HADOOP-2139 (phase 2) Make region server more event driven - HADOOP-2289 Useless efforts of looking for the non-existant table in select - command. - (Edward Yoon via Stack) - HADOOP-2257 Show a total of all requests and regions on the web ui - (Paul Saab via Stack) - HADOOP-2261 HTable.abort no longer throws exception if there is no active update. - HADOOP-2287 Make hbase unit tests take less time to complete. - HADOOP-2262 Retry n times instead of n**2 times. - HADOOP-1608 Relational Algrebra Operators - (Edward Yoon via Stack) - HADOOP-2198 HTable should have method to return table metadata - HADOOP-2296 hbase shell: phantom columns show up from select command - HADOOP-2297 System.exit() Handling in hbase shell jar command - (Edward Yoon via Stack) - HADOOP-2224 Add HTable.getRow(ROW, ts) - (Bryan Duxbury via Stack) - HADOOP-2339 Delete command with no WHERE clause - (Edward Yoon via Stack) - HADOOP-2299 Support inclusive scans (Bryan Duxbury via Stack) - HADOOP-2333 Client side retries happen at the wrong level - HADOOP-2357 Compaction cleanup; less deleting + prevent possible file leaks - HADOOP-2392 TestRegionServerExit has new failure mode since HADOOP-2338 - HADOOP-2370 Allow column families with an unlimited number of versions - (Edward Yoon via Stack) - HADOOP-2047 Add an '--master=X' and '--html' command-line parameters to shell - (Edward Yoon via Stack) - HADOOP-2351 If select command returns no result, it doesn't need to show the - header information (Edward Yoon via Stack) - HADOOP-2285 Add being able to shutdown regionservers (Dennis Kubes via Stack) - HADOOP-2458 HStoreFile.writeSplitInfo should just call - HStoreFile.Reference.write - HADOOP-2471 Add reading/writing MapFile to PerformanceEvaluation suite - HADOOP-2522 Separate MapFile benchmark from PerformanceEvaluation - (Tom White via Stack) - HADOOP-2502 Insert/Select timestamp, Timestamp data type in HQL - (Edward Yoon via Stack) - HADOOP-2450 Show version (and svn revision) in hbase web ui - HADOOP-2472 Range selection using filter (Edward Yoon via Stack) - HADOOP-2548 Make TableMap and TableReduce generic - (Frederik Hedberg via Stack) - HADOOP-2557 Shell count function (Edward Yoon via Stack) - HADOOP-2589 Change an classes/package name from Shell to hql - (Edward Yoon via Stack) - HADOOP-2545 hbase rest server should be started with hbase-daemon.sh - HADOOP-2525 Same 2 lines repeated 11 million times in HMaster log upon - HMaster shutdown - HADOOP-2616 hbase not spliting when the total size of region reaches max - region size * 1.5 - HADOOP-2643 Make migration tool smarter. - -Release 0.15.1 -Branch 0.15 - - INCOMPATIBLE CHANGES - HADOOP-1931 Hbase scripts take --ARG=ARG_VALUE when should be like hadoop - and do ---ARG ARG_VALUE - - NEW FEATURES - HADOOP-1768 FS command using Hadoop FsShell operations - (Edward Yoon via Stack) - HADOOP-1784 Delete: Fix scanners and gets so they work properly in presence - of deletes. Added a deleteAll to remove all cells equal to or - older than passed timestamp. Fixed compaction so deleted cells - do not make it out into compacted output. Ensure also that - versions > column max are dropped compacting. - HADOOP-1720 Addition of HQL (Hbase Query Language) support in Hbase Shell. - The old shell syntax has been replaced by HQL, a small SQL-like - set of operators, for creating, altering, dropping, inserting, - deleting, and selecting, etc., data in hbase. - (Inchul Song and Edward Yoon via Stack) - HADOOP-1913 Build a Lucene index on an HBase table - (Ning Li via Stack) - HADOOP-1957 Web UI with report on cluster state and basic browsing of tables - - OPTIMIZATIONS - - BUG FIXES - HADOOP-1527 Region server won't start because logdir exists - HADOOP-1723 If master asks region server to shut down, by-pass return of - shutdown message - HADOOP-1729 Recent renaming or META tables breaks hbase shell - HADOOP-1730 unexpected null value causes META scanner to exit (silently) - HADOOP-1747 On a cluster, on restart, regions multiply assigned - HADOOP-1776 Fix for sporadic compaction failures closing and moving - compaction result - HADOOP-1780 Regions are still being doubly assigned - HADOOP-1797 Fix NPEs in MetaScanner constructor - HADOOP-1799 Incorrect classpath in binary version of Hadoop - HADOOP-1805 Region server hang on exit - HADOOP-1785 TableInputFormat.TableRecordReader.next has a bug - (Ning Li via Stack) - HADOOP-1800 output should default utf8 encoding - HADOOP-1801 When hdfs is yanked out from under hbase, hbase should go down gracefully - HADOOP-1813 OOME makes zombie of region server - HADOOP-1814 TestCleanRegionServerExit fails too often on Hudson - HADOOP-1820 Regionserver creates hlogs without bound - (reverted 2007/09/25) (Fixed 2007/09/30) - HADOOP-1821 Replace all String.getBytes() with String.getBytes("UTF-8") - HADOOP-1832 listTables() returns duplicate tables - HADOOP-1834 Scanners ignore timestamp passed on creation - HADOOP-1847 Many HBase tests do not fail well. - HADOOP-1847 Many HBase tests do not fail well. (phase 2) - HADOOP-1870 Once file system failure has been detected, don't check it again - and get on with shutting down the hbase cluster. - HADOOP-1888 NullPointerException in HMemcacheScanner (reprise) - HADOOP-1903 Possible data loss if Exception happens between snapshot and - flush to disk. - HADOOP-1920 Wrapper scripts broken when hadoop in one location and hbase in - another - HADOOP-1923, HADOOP-1924 a) tests fail sporadically because set up and tear - down is inconsistent b) TestDFSAbort failed in nightly #242 - HADOOP-1929 Add hbase-default.xml to hbase jar - HADOOP-1941 StopRowFilter throws NPE when passed null row - HADOOP-1966 Make HBase unit tests more reliable in the Hudson environment. - HADOOP-1975 HBase tests failing with java.lang.NumberFormatException - HADOOP-1990 Regression test instability affects nightly and patch builds - HADOOP-1996 TestHStoreFile fails on windows if run multiple times - HADOOP-1937 When the master times out a region server's lease, it is too - aggressive in reclaiming the server's log. - HADOOP-2004 webapp hql formatting bugs - HADOOP_2011 Make hbase daemon scripts take args in same order as hadoop - daemon scripts - HADOOP-2017 TestRegionServerAbort failure in patch build #903 and - nightly #266 - HADOOP-2029 TestLogRolling fails too often in patch and nightlies - HADOOP-2038 TestCleanRegionExit failed in patch build #927 - - IMPROVEMENTS - HADOOP-1737 Make HColumnDescriptor data publically members settable - HADOOP-1746 Clean up findbugs warnings - HADOOP-1757 Bloomfilters: single argument constructor, use enum for bloom - filter types - HADOOP-1760 Use new MapWritable and SortedMapWritable classes from - org.apache.hadoop.io - HADOOP-1793 (Phase 1) Remove TestHClient (Phase2) remove HClient. - HADOOP-1794 Remove deprecated APIs - HADOOP-1802 Startup scripts should wait until hdfs as cleared 'safe mode' - HADOOP-1833 bin/stop_hbase.sh returns before it completes - (Izaak Rubin via Stack) - HADOOP-1835 Updated Documentation for HBase setup/installation - (Izaak Rubin via Stack) - HADOOP-1868 Make default configuration more responsive - HADOOP-1884 Remove useless debugging log messages from hbase.mapred - HADOOP-1856 Add Jar command to hbase shell using Hadoop RunJar util - (Edward Yoon via Stack) - HADOOP-1928 Have master pass the regionserver the filesystem to use - HADOOP-1789 Output formatting - HADOOP-1960 If a region server cannot talk to the master before its lease - times out, it should shut itself down - HADOOP-2035 Add logo to webapps - - -Below are the list of changes before 2007-08-18 - - 1. HADOOP-1384. HBase omnibus patch. (jimk, Vuk Ercegovac, and Michael Stack) - 2. HADOOP-1402. Fix javadoc warnings in hbase contrib. (Michael Stack) - 3. HADOOP-1404. HBase command-line shutdown failing (Michael Stack) - 4. HADOOP-1397. Replace custom hbase locking with - java.util.concurrent.locks.ReentrantLock (Michael Stack) - 5. HADOOP-1403. HBase reliability - make master and region server more fault - tolerant. - 6. HADOOP-1418. HBase miscellaneous: unit test for HClient, client to do - 'Performance Evaluation', etc. - 7. HADOOP-1420, HADOOP-1423. Findbugs changes, remove reference to removed - class HLocking. - 8. HADOOP-1424. TestHBaseCluster fails with IllegalMonitorStateException. Fix - regression introduced by HADOOP-1397. - 9. HADOOP-1426. Make hbase scripts executable + add test classes to CLASSPATH. - 10. HADOOP-1430. HBase shutdown leaves regionservers up. - 11. HADOOP-1392. Part1: includes create/delete table; enable/disable table; - add/remove column. - 12. HADOOP-1392. Part2: includes table compaction by merging adjacent regions - that have shrunk in size. - 13. HADOOP-1445 Support updates across region splits and compactions - 14. HADOOP-1460 On shutdown IOException with complaint 'Cannot cancel lease - that is not held' - 15. HADOOP-1421 Failover detection, split log files. - For the files modified, also clean up javadoc, class, field and method - visibility (HADOOP-1466) - 16. HADOOP-1479 Fix NPE in HStore#get if store file only has keys < passed key. - 17. HADOOP-1476 Distributed version of 'Performance Evaluation' script - 18. HADOOP-1469 Asychronous table creation - 19. HADOOP-1415 Integrate BSD licensed bloom filter implementation. - 20. HADOOP-1465 Add cluster stop/start scripts for hbase - 21. HADOOP-1415 Provide configurable per-column bloom filters - part 2. - 22. HADOOP-1498. Replace boxed types with primitives in many places. - 23. HADOOP-1509. Made methods/inner classes in HRegionServer and HClient protected - instead of private for easier extension. Also made HRegion and HRegionInfo public too. - Added an hbase-default.xml property for specifying what HRegionInterface extension to use - for proxy server connection. (James Kennedy via Jim Kellerman) - 24. HADOOP-1534. [hbase] Memcache scanner fails if start key not present - 25. HADOOP-1537. Catch exceptions in testCleanRegionServerExit so we can see - what is failing. - 26. HADOOP-1543 [hbase] Add HClient.tableExists - 27. HADOOP-1519 [hbase] map/reduce interface for HBase. (Vuk Ercegovac and - Jim Kellerman) - 28. HADOOP-1523 Hung region server waiting on write locks - 29. HADOOP-1560 NPE in MiniHBaseCluster on Windows - 30. HADOOP-1531 Add RowFilter to HRegion.HScanner - Adds a row filtering interface and two implemenentations: A page scanner, - and a regex row/column-data matcher. (James Kennedy via Stack) - 31. HADOOP-1566 Key-making utility - 32. HADOOP-1415 Provide configurable per-column bloom filters. - HADOOP-1466 Clean up visibility and javadoc issues in HBase. - 33. HADOOP-1538 Provide capability for client specified time stamps in HBase - HADOOP-1466 Clean up visibility and javadoc issues in HBase. - 34. HADOOP-1589 Exception handling in HBase is broken over client server connections - 35. HADOOP-1375 a simple parser for hbase (Edward Yoon via Stack) - 36. HADOOP-1600 Update license in HBase code - 37. HADOOP-1589 Exception handling in HBase is broken over client server - 38. HADOOP-1574 Concurrent creates of a table named 'X' all succeed - 39. HADOOP-1581 Un-openable tablename bug - 40. HADOOP-1607 [shell] Clear screen command (Edward Yoon via Stack) - 41. HADOOP-1614 [hbase] HClient does not protect itself from simultaneous updates - 42. HADOOP-1468 Add HBase batch update to reduce RPC overhead - 43. HADOOP-1616 Sporadic TestTable failures - 44. HADOOP-1615 Replacing thread notification-based queue with - java.util.concurrent.BlockingQueue in HMaster, HRegionServer - 45. HADOOP-1606 Updated implementation of RowFilterSet, RowFilterInterface - (Izaak Rubin via Stack) - 46. HADOOP-1579 Add new WhileMatchRowFilter and StopRowFilter filters - (Izaak Rubin via Stack) - 47. HADOOP-1637 Fix to HScanner to Support Filters, Add Filter Tests to - TestScanner2 (Izaak Rubin via Stack) - 48. HADOOP-1516 HClient fails to readjust when ROOT or META redeployed on new - region server - 49. HADOOP-1646 RegionServer OOME's under sustained, substantial loading by - 10 concurrent clients - 50. HADOOP-1468 Add HBase batch update to reduce RPC overhead (restrict batches - to a single row at a time) - 51. HADOOP-1528 HClient for multiple tables (phase 1) (James Kennedy & JimK) - 52. HADOOP-1528 HClient for multiple tables (phase 2) all HBase client side code - (except TestHClient and HBaseShell) have been converted to use the new client - side objects (HTable/HBaseAdmin/HConnection) instead of HClient. - 53. HADOOP-1528 HClient for multiple tables - expose close table function - 54. HADOOP-1466 Clean up warnings, visibility and javadoc issues in HBase. - 55. HADOOP-1662 Make region splits faster - 56. HADOOP-1678 On region split, master should designate which host should - serve daughter splits. Phase 1: Master balances load for new regions and - when a region server fails. - 57. HADOOP-1678 On region split, master should designate which host should - serve daughter splits. Phase 2: Master assigns children of split region - instead of HRegionServer serving both children. - 58. HADOOP-1710 All updates should be batch updates - 59. HADOOP-1711 HTable API should use interfaces instead of concrete classes as - method parameters and return values - 60. HADOOP-1644 Compactions should not block updates - 60. HADOOP-1672 HBase Shell should use new client classes - (Edward Yoon via Stack). - 61. HADOOP-1709 Make HRegionInterface more like that of HTable - HADOOP-1725 Client find of table regions should not include offlined, split parents +Hbase Change Log + +Release 0.3.0 - Unreleased + + INCOMPATIBLE CHANGES + BUG FIXES + HBASE-805 Remove unnecessary getRow overloads in HRS (Jonathan Gray via + Jim Kellerman) (Fix whitespace diffs in HRegionServer) + HBASE-811 HTD is not fully copyable (Andrew Purtell via Jim Kellerman) + HBASE-729 Client region/metadata cache should have a public method for + invalidating entries (Andrew Purtell via Stack) + HBASE-819 Remove DOS-style ^M carriage returns from all code where found + (Jonathan Gray via Jim Kellerman) + + IMPROVEMENTS + HBASE-801 When a table haven't disable, shell could response in a "user + friendly" way. + HBASE-816 TableMap should survive USE (Andrew Purtell via Stack) + + NEW FEATURES + OPTIMIZATIONS + +Release 0.2.0 - August 8, 2008. + + INCOMPATIBLE CHANGES + HBASE-584 Names in the filter interface are confusing (Clint Morgan via + Jim Kellerman) (API change for filters) + HBASE-601 Just remove deprecated methods in HTable; 0.2 is not backward + compatible anyways + HBASE-82 Row keys should be array of bytes + HBASE-76 Purge servers of Text (Done as part of HBASE-82 commit). + HBASE-487 Replace hql w/ a hbase-friendly jirb or jython shell + Part 1: purge of hql and added raw jirb in its place. + HBASE-521 Improve client scanner interface + HBASE-288 Add in-memory caching of data. Required update of hadoop to + 0.17.0-dev.2008-02-07_12-01-58. (Tom White via Stack) + HBASE-696 Make bloomfilter true/false and self-sizing + HBASE-720 clean up inconsistencies around deletes (Izaak Rubin via Stack) + HBASE-796 Deprecates Text methods from HTable + (Michael Gottesman via Stack) + + BUG FIXES + HBASE-574 HBase does not load hadoop native libs (Rong-En Fan via Stack) + HBASE-598 Loggging, no .log file; all goes into .out + HBASE-622 Remove StaticTestEnvironment and put a log4j.properties in src/test + HBASE-624 Master will shut down if number of active region servers is zero + even if shutdown was not requested + HBASE-629 Split reports incorrect elapsed time + HBASE-623 Migration script for hbase-82 + HBASE-630 Default hbase.rootdir is garbage + HBASE-589 Remove references to deprecated methods in Hadoop once + hadoop-0.17.0 is released + HBASE-638 Purge \r from src + HBASE-644 DroppedSnapshotException but RegionServer doesn't restart + HBASE-641 Improve master split logging + HBASE-642 Splitting log in a hostile environment -- bad hdfs -- we drop + write-ahead-log edits + HBASE-646 EOFException opening HStoreFile info file (spin on HBASE-645and 550) + HBASE-648 If mapfile index is empty, run repair + HBASE-640 TestMigrate failing on hudson + HBASE-651 Table.commit should throw NoSuchColumnFamilyException if column + family doesn't exist + HBASE-649 API polluted with default and protected access data members and methods + HBASE-650 Add String versions of get, scanner, put in HTable + HBASE-656 Do not retry exceptions such as unknown scanner or illegal argument + HBASE-659 HLog#cacheFlushLock not cleared; hangs a region + HBASE-663 Incorrect sequence number for cache flush + HBASE-655 Need programmatic way to add column family: need programmatic way + to enable/disable table + HBASE-654 API HTable.getMetadata().addFamily shouldn't be exposed to user + HBASE-666 UnmodifyableHRegionInfo gives the wrong encoded name + HBASE-668 HBASE-533 broke build + HBASE-670 Historian deadlocks if regionserver is at global memory boundary + and is hosting .META. + HBASE-665 Server side scanner doesn't honor stop row + HBASE-662 UI in table.jsp gives META locations, not the table's regions + location (Jean-Daniel Cryans via Stack) + HBASE-676 Bytes.getInt returns a long (Clint Morgan via Stack) + HBASE-680 Config parameter hbase.io.index.interval should be + hbase.index.interval, according to HBaseMapFile.HbaseWriter + (LN via Stack) + HBASE-682 Unnecessary iteration in HMemcache.internalGet? got much better + reading performance after break it (LN via Stack) + HBASE-686 MemcacheScanner didn't return the first row(if it exists), + because HScannerInterface's output incorrect (LN via Jim Kellerman) + HBASE-691 get* and getScanner are different in how they treat column parameter + HBASE-694 HStore.rowAtOrBeforeFromMapFile() fails to locate the row if # of mapfiles >= 2 + (Rong-En Fan via Bryan) + HBASE-652 dropping table fails silently if table isn't disabled + HBASE-683 can not get svn revision # at build time if locale is not english + (Rong-En Fan via Stack) + HBASE-699 Fix TestMigrate up on Hudson + HBASE-615 Region balancer oscillates during cluster startup + HBASE-613 Timestamp-anchored scanning fails to find all records + HBASE-681 NPE in Memcache + HBASE-701 Showing bytes in log when should be String + HBASE-702 deleteall doesn't + HBASE-704 update new shell docs and commands on help menu + HBASE-709 Deadlock while rolling WAL-log while finishing flush + HBASE-710 If clocks are way off, then we can have daughter split come + before rather than after its parent in .META. + HBASE-714 Showing bytes in log when should be string (2) + HBASE-627 Disable table doesn't work reliably + HBASE-716 TestGet2.testGetClosestBefore fails with hadoop-0.17.1 + HBASE-715 Base HBase 0.2 on Hadoop 0.17.1 + HBASE-718 hbase shell help info + HBASE-717 alter table broke with new shell returns InvalidColumnNameException + HBASE-573 HBase does not read hadoop-*.xml for dfs configuration after + moving out hadoop/contrib + HBASE-11 Unexpected exits corrupt DFS + HBASE-12 When hbase regionserver restarts, it says "impossible state for + createLease()" + HBASE-575 master dies with stack overflow error if rootdir isn't qualified + HBASE-582 HBase 554 forgot to clear results on each iteration caused by a filter + (Clint Morgan via Stack) + HBASE-532 Odd interaction between HRegion.get, HRegion.deleteAll and compactions + HBASE-10 HRegionServer hangs upon exit due to DFSClient Exception + HBASE-595 RowFilterInterface.rowProcessed() is called *before* fhe final + filtering decision is made (Clint Morgan via Stack) + HBASE-586 HRegion runs HStore memcache snapshotting -- fix it so only HStore + knows about workings of memcache + HBASE-588 Still a 'hole' in scanners, even after HBASE-532 + HBASE-604 Don't allow CLASSPATH from environment pollute the hbase CLASSPATH + HBASE-608 HRegionServer::getThisIP() checks hadoop config var for dns interface name + (Jim R. Wilson via Stack) + HBASE-609 Master doesn't see regionserver edits because of clock skew + HBASE-607 MultiRegionTable.makeMultiRegionTable is not deterministic enough + for regression tests + HBASE-405 TIF and TOF use log4j directly rather than apache commons-logging + HBASE-618 We always compact if 2 files, regardless of the compaction threshold setting + HBASE-619 Fix 'logs' link in UI + HBASE-478 offlining of table does not run reliably + HBASE-453 undeclared throwable exception from HTable.get + HBASE-620 testmergetool failing in branch and trunk since hbase-618 went in + HBASE-550 EOF trying to read reconstruction log stops region deployment + HBASE-551 Master stuck splitting server logs in shutdown loop; on each + iteration, edits are aggregated up into the millions + HBASE-505 Region assignments should never time out so long as the region + server reports that it is processing the open request + HBASE-561 HBase package does not include LICENSE.txt nor build.xml + HBASE-563 TestRowFilterAfterWrite erroneously sets master address to + 0.0.0.0:60100 rather than relying on conf + HBASE-507 Use Callable pattern to sleep between retries + HBASE-564 Don't do a cache flush if there are zero entries in the cache. + HBASE-554 filters generate StackOverflowException + HBASE-567 Reused BatchUpdate instances accumulate BatchOperations + HBASE-577 NPE getting scanner + HBASE-19 CountingBloomFilter can overflow its storage + (Stu Hood and Bryan Duxbury via Stack) + HBASE-28 thrift put/mutateRow methods need to throw IllegalArgument + exceptions (Dave Simpson via Bryan Duxbury via Stack) + HBASE-2 hlog numbers should wrap around when they reach 999 + (Bryan Duxbury via Stack) + HBASE-421 TestRegionServerExit broken + HBASE-426 hbase can't find remote filesystem + HBASE-437 Clear Command should use system.out (Edward Yoon via Stack) + HBASE-434, HBASE-435 TestTableIndex and TestTableMapReduce failed in Hudson builds + HBASE-446 Fully qualified hbase.rootdir doesn't work + HBASE-438 XMLOutputter state should be initialized. (Edward Yoon via Stack) + HBASE-8 Delete table does not remove the table directory in the FS + HBASE-428 Under continuous upload of rows, WrongRegionExceptions are thrown + that reach the client even after retries + HBASE-460 TestMigrate broken when HBase moved to subproject + HBASE-462 Update migration tool + HBASE-473 When a table is deleted, master sends multiple close messages to + the region server + HBASE-490 Doubly-assigned .META.; master uses one and clients another + HBASE-492 hbase TRUNK does not build against hadoop TRUNK + HBASE-496 impossible state for createLease writes 400k lines in about 15mins + HBASE-472 Passing on edits, we dump all to log + HBASE-495 No server address listed in .META. + HBASE-433 HBASE-251 Region server should delete restore log after successful + restore, Stuck replaying the edits of crashed machine. + HBASE-27 hregioninfo cell empty in meta table + HBASE-501 Empty region server address in info:server entry and a + startcode of -1 in .META. + HBASE-516 HStoreFile.finalKey does not update the final key if it is not + the top region of a split region + HBASE-525 HTable.getRow(Text) does not work (Clint Morgan via Bryan Duxbury) + HBASE-524 Problems with getFull + HBASE-528 table 'does not exist' when it does + HBASE-531 Merge tool won't merge two overlapping regions (port HBASE-483 to + trunk) + HBASE-537 Wait for hdfs to exit safe mode + HBASE-476 RegexpRowFilter behaves incorectly when there are multiple store + files (Clint Morgan via Jim Kellerman) + HBASE-527 RegexpRowFilter does not work when there are columns from + multiple families (Clint Morgan via Jim Kellerman) + HBASE-534 Double-assignment at SPLIT-time + HBASE-712 midKey found compacting is the first, not necessarily the optimal + HBASE-719 Find out why users have network problems in HBase and not in Hadoop + and HConnectionManager (Jean-Daniel Cryans via Stack) + HBASE-703 Invalid regions listed by regionserver.jsp (Izaak Rubin via Stack) + HBASE-674 Memcache size unreliable + HBASE-726 Unit tests won't run because of a typo (Sebastien Rainville via Stack) + HBASE-727 Client caught in an infinite loop when trying to connect to cached + server locations (Izaak Rubin via Stack) + HBASE-732 shell formatting error with the describe command + (Izaak Rubin via Stack) + HBASE-731 delete, deletefc in HBase shell do not work correctly + (Izaak Rubin via Stack) + HBASE-734 scan '.META.', {LIMIT => 10} crashes (Izaak Rubin via Stack) + HBASE-736 Should have HTable.deleteAll(String row) and HTable.deleteAll(Text row) + (Jean-Daniel Cryans via Stack) + HBASE-740 ThriftServer getting table names incorrectly (Tim Sell via Stack) + HBASE-742 Rename getMetainfo in HTable as getTableDescriptor + HBASE-739 HBaseAdmin.createTable() using old HTableDescription doesn't work + (Izaak Rubin via Stack) + HBASE-744 BloomFilter serialization/deserialization broken + HBASE-742 Column length limit is not enforced (Jean-Daniel Cryans via Stack) + HBASE-737 Scanner: every cell in a row has the same timestamp + HBASE-700 hbase.io.index.interval need be configuratable in column family + (Andrew Purtell via Stack) + HBASE-62 Allow user add arbitrary key/value pairs to table and column + descriptors (Andrew Purtell via Stack) + HBASE-34 Set memcache flush size per column (Andrew Purtell via Stack) + HBASE-42 Set region split size on table creation (Andrew Purtell via Stack) + HBASE-43 Add a read-only attribute to columns (Andrew Purtell via Stack) + HBASE-424 Should be able to enable/disable .META. table + HBASE-679 Regionserver addresses are still not right in the new tables page + HBASE-758 Throwing IOE read-only when should be throwing NSRE + HBASE-743 bin/hbase migrate upgrade fails when redo logs exists + HBASE-754 The JRuby shell documentation is wrong in "get" and "put" + (Jean-Daniel Cryans via Stack) + HBASE-756 In HBase shell, the put command doesn't process the timestamp + (Jean-Daniel Cryans via Stack) + HBASE-757 REST mangles table names (Sishen via Stack) + HBASE-706 On OOME, regionserver sticks around and doesn't go down with cluster + (Jean-Daniel Cryans via Stack) + HBASE-759 TestMetaUtils failing on hudson + HBASE-761 IOE: Stream closed exception all over logs + HBASE-763 ClassCastException from RowResult.get(String) + (Andrew Purtell via Stack) + HBASE-764 The name of column request has padding zero using REST interface + (Sishen Freecity via Stack) + HBASE-750 NPE caused by StoreFileScanner.updateReaders + HBASE-769 TestMasterAdmin fails throwing RegionOfflineException when we're + expecting IllegalStateException + HBASE-766 FileNotFoundException trying to load HStoreFile 'data' + HBASE-770 Update HBaseRPC to match hadoop 0.17 RPC + HBASE-780 Can't scan '.META.' from new shell + HBASE-424 Should be able to enable/disable .META. table + HBASE-771 Names legal in 0.1 are not in 0.2; breaks migration + HBASE-788 Div by zero in Master.jsp (Clint Morgan via Jim Kellerman) + HBASE-791 RowCount doesn't work (Jean-Daniel Cryans via Stack) + HBASE-751 dfs exception and regionserver stuck during heavy write load + HBASE-793 HTable.getStartKeys() ignores table names when matching columns + (Andrew Purtell and Dru Jensen via Stack) + HBASE-790 During import, single region blocks requests for >10 minutes, + thread dumps, throws out pending requests, and continues + (Jonathan Gray via Stack) + + IMPROVEMENTS + HBASE-559 MR example job to count table rows + HBASE-596 DemoClient.py (Ivan Begtin via Stack) + HBASE-581 Allow adding filters to TableInputFormat (At same time, ensure TIF + is subclassable) (David Alves via Stack) + HBASE-603 When an exception bubbles out of getRegionServerWithRetries, wrap + the exception with a RetriesExhaustedException + HBASE-600 Filters have excessive DEBUG logging + HBASE-611 regionserver should do basic health check before reporting + alls-well to the master + HBASE-614 Retiring regions is not used; exploit or remove + HBASE-538 Improve exceptions that come out on client-side + HBASE-569 DemoClient.php (Jim R. Wilson via Stack) + HBASE-522 Where new Text(string) might be used in client side method calls, + add an overload that takes String (Done as part of HBASE-82) + HBASE-570 Remove HQL unit test (Done as part of HBASE-82 commit). + HBASE-626 Use Visitor pattern in MetaRegion to reduce code clones in HTable + and HConnectionManager (Jean-Daniel Cryans via Stack) + HBASE-621 Make MAX_VERSIONS work like TTL: In scans and gets, check + MAX_VERSIONs setting and return that many only rather than wait on + compaction (Jean-Daniel Cryans via Stack) + HBASE-504 Allow HMsg's carry a payload: e.g. exception that happened over + on the remote side. + HBASE-583 RangeRowFilter/ColumnValueFilter to allow choice of rows based on + a (lexicographic) comparison to column's values + (Clint Morgan via Stack) + HBASE-579 Add hadoop 0.17.x + HBASE-660 [Migration] addColumn/deleteColumn functionality in MetaUtils + HBASE-632 HTable.getMetadata is very inefficient + HBASE-671 New UI page displaying all regions in a table should be sorted + HBASE-672 Sort regions in the regionserver UI + HBASE-677 Make HTable, HRegion, HRegionServer, HStore, and HColumnDescriptor + subclassable (Clint Morgan via Stack) + HBASE-682 Regularize toString + HBASE-672 Sort regions in the regionserver UI + HBASE-469 Streamline HStore startup and compactions + HBASE-544 Purge startUpdate from internal code and test cases + HBASE-557 HTable.getRow() should receive RowResult objects + HBASE-452 "region offline" should throw IOException, not IllegalStateException + HBASE-541 Update hadoop jars. + HBASE-523 package-level javadoc should have example client + HBASE-415 Rewrite leases to use DelayedBlockingQueue instead of polling + HBASE-35 Make BatchUpdate public in the API + HBASE-409 Add build path to svn:ignore list (Edward Yoon via Stack) + HBASE-408 Add .classpath and .project to svn:ignore list + (Edward Yoon via Stack) + HBASE-410 Speed up the test suite (make test timeout 5 instead of 15 mins). + HBASE-281 Shell should allow deletions in .META. and -ROOT- tables + (Edward Yoon & Bryan Duxbury via Stack) + HBASE-56 Unnecessary HQLClient Object creation in a shell loop + (Edward Yoon via Stack) + HBASE-3 rest server: configure number of threads for jetty + (Bryan Duxbury via Stack) + HBASE-416 Add apache-style logging to REST server and add setting log + level, etc. + HBASE-406 Remove HTable and HConnection close methods + (Bryan Duxbury via Stack) + HBASE-418 Move HMaster and related classes into master package + (Bryan Duxbury via Stack) + HBASE-410 Speed up the test suite - Apparently test timeout was too + aggressive for Hudson. TestLogRolling timed out even though it + was operating properly. Change test timeout to 10 minutes. + HBASE-436 website: http://hadoop.apache.org/hbase + HBASE-417 Factor TableOperation and subclasses into separate files from + HMaster (Bryan Duxbury via Stack) + HBASE-440 Add optional log roll interval so that log files are garbage + collected + HBASE-407 Keep HRegionLocation information in LRU structure + HBASE-444 hbase is very slow at determining table is not present + HBASE-438 XMLOutputter state should be initialized. + HBASE-414 Move client classes into client package + HBASE-79 When HBase needs to be migrated, it should display a message on + stdout, not just in the logs + HBASE-461 Simplify leases. + HBASE-419 Move RegionServer and related classes into regionserver package + HBASE-457 Factor Master into Master, RegionManager, and ServerManager + HBASE-464 HBASE-419 introduced javadoc errors + HBASE-468 Move HStoreKey back to o.a.h.h + HBASE-442 Move internal classes out of HRegionServer + HBASE-466 Move HMasterInterface, HRegionInterface, and + HMasterRegionInterface into o.a.h.h.ipc + HBASE-479 Speed up TestLogRolling + HBASE-480 Tool to manually merge two regions + HBASE-477 Add support for an HBASE_CLASSPATH + HBASE-443 Move internal classes out of HStore + HBASE-515 At least double default timeouts between regionserver and master + HBASE-529 RegionServer needs to recover if datanode goes down + HBASE-456 Clearly state which ports need to be opened in order to run HBase + HBASE-536 Remove MiniDFS startup from MiniHBaseCluster + HBASE-521 Improve client scanner interface + HBASE-562 Move Exceptions to subpackages (Jean-Daniel Cryans via Stack) + HBASE-631 HTable.getRow() for only a column family + (Jean-Daniel Cryans via Stack) + HBASE-731 Add a meta refresh tag to the Web ui for master and region server + (Jean-Daniel Cryans via Stack) + HBASE-735 hbase shell doesn't trap CTRL-C signal (Jean-Daniel Cryans via Stack) + HBASE-730 On startup, rinse STARTCODE and SERVER from .META. + (Jean-Daniel Cryans via Stack) + HBASE-738 overview.html in need of updating (Izaak Rubin via Stack) + HBASE-745 scaling of one regionserver, improving memory and cpu usage (partial) + (LN via Stack) + HBASE-746 Batching row mutations via thrift (Tim Sell via Stack) + HBASE-772 Up default lease period from 60 to 120 seconds + HBASE-779 Test changing hbase.hregion.memcache.block.multiplier to 2 + HBASE-783 For single row, single family retrieval, getRow() works half + as fast as getScanner().next() (Jean-Daniel Cryans via Stack) + HBASE-789 add clover coverage report targets (Rong-en Fan via Stack) + + NEW FEATURES + HBASE-47 Option to set TTL for columns in hbase + (Andrew Purtell via Bryan Duxbury and Stack) + HBASE-23 UI listing regions should be sorted by address and show additional + region state (Jean-Daniel Cryans via Stack) + HBASE-639 Add HBaseAdmin.getTableDescriptor function + HBASE-533 Region Historian + HBASE-487 Replace hql w/ a hbase-friendly jirb or jython shell + HBASE-548 Tool to online single region + HBASE-71 Master should rebalance region assignments periodically + HBASE-512 Add configuration for global aggregate memcache size + HBASE-40 Add a method of getting multiple (but not all) cells for a row + at once + HBASE-506 When an exception has to escape ServerCallable due to exhausted + retries, show all the exceptions that lead to this situation + HBASE-747 Add a simple way to do batch updates of many rows (Jean-Daniel + Cryans via JimK) + HBASE-733 Enhance Cell so that it can contain multiple values at multiple + timestamps + HBASE-511 Do exponential backoff in clients on NSRE, WRE, ISE, etc. + (Andrew Purtell via Jim Kellerman) + + OPTIMIZATIONS + HBASE-430 Performance: Scanners and getRow return maps with duplicate data + +Release 0.1.3 - 07/25/2008 + + BUG FIXES + HBASE-644 DroppedSnapshotException but RegionServer doesn't restart + HBASE-645 EOFException opening region (HBASE-550 redux) + HBASE-641 Improve master split logging + HBASE-642 Splitting log in a hostile environment -- bad hdfs -- we drop + write-ahead-log edits + HBASE-646 EOFException opening HStoreFile info file (spin on HBASE-645 and 550) + HBASE-648 If mapfile index is empty, run repair + HBASE-659 HLog#cacheFlushLock not cleared; hangs a region + HBASE-663 Incorrect sequence number for cache flush + HBASE-652 Dropping table fails silently if table isn't disabled + HBASE-674 Memcache size unreliable + HBASE-665 server side scanner doesn't honor stop row + HBASE-681 NPE in Memcache (Clint Morgan via Jim Kellerman) + HBASE-680 config parameter hbase.io.index.interval should be + hbase.index.interval, accroding to HBaseMapFile.HbaseWriter + (LN via Stack) + HBASE-684 unnecessary iteration in HMemcache.internalGet? got much better + reading performance after break it (LN via Stack) + HBASE-686 MemcacheScanner didn't return the first row(if it exists), + because HScannerInterface's output incorrect (LN via Jim Kellerman) + HBASE-613 Timestamp-anchored scanning fails to find all records + HBASE-709 Deadlock while rolling WAL-log while finishing flush + HBASE-707 High-load import of data into single table/family never triggers split + HBASE-710 If clocks are way off, then we can have daughter split come + before rather than after its parent in .META. + +Release 0.1.2 - 05/13/2008 + + BUG FIXES + HBASE-577 NPE getting scanner + HBASE-574 HBase does not load hadoop native libs (Rong-En Fan via Stack). + HBASE-11 Unexpected exits corrupt DFS - best we can do until we have at + least a subset of HADOOP-1700 + HBASE-573 HBase does not read hadoop-*.xml for dfs configuration after + moving out hadoop/contrib + HBASE-12 when hbase regionserver restarts, it says "impossible state for + createLease()" + HBASE-575 master dies with stack overflow error if rootdir isn't qualified + HBASE-500 Regionserver stuck on exit + HBASE-582 HBase 554 forgot to clear results on each iteration caused by a filter + (Clint Morgan via Stack) + HBASE-532 Odd interaction between HRegion.get, HRegion.deleteAll and compactions + HBASE-590 HBase migration tool does not get correct FileSystem or root + directory if configuration is not correct + HBASE-595 RowFilterInterface.rowProcessed() is called *before* fhe final + filtering decision is made (Clint Morgan via Stack) + HBASE-586 HRegion runs HStore memcache snapshotting -- fix it so only HStore + knows about workings of memcache + HBASE-572 Backport HBASE-512 to 0.1 branch + HBASE-588 Still a 'hole' in scanners, even after HBASE-532 + HBASE-604 Don't allow CLASSPATH from environment pollute the hbase CLASSPATH + HBASE-608 HRegionServer::getThisIP() checks hadoop config var for dns interface name + (Jim R. Wilson via Stack) + HBASE-609 Master doesn't see regionserver edits because of clock skew + HBASE-607 MultiRegionTable.makeMultiRegionTable is not deterministic enough + for regression tests + HBASE-478 offlining of table does not run reliably + HBASE-618 We always compact if 2 files, regardless of the compaction threshold setting + HBASE-619 Fix 'logs' link in UI + HBASE-620 testmergetool failing in branch and trunk since hbase-618 went in + + IMPROVEMENTS + HBASE-559 MR example job to count table rows + HBASE-578 Upgrade branch to 0.16.3 hadoop. + HBASE-596 DemoClient.py (Ivan Begtin via Stack) + + +Release 0.1.1 - 04/11/2008 + + BUG FIXES + HBASE-550 EOF trying to read reconstruction log stops region deployment + HBASE-551 Master stuck splitting server logs in shutdown loop; on each + iteration, edits are aggregated up into the millions + HBASE-505 Region assignments should never time out so long as the region + server reports that it is processing the open request + HBASE-552 Fix bloom filter bugs (Andrzej Bialecki via Jim Kellerman) + HBASE-507 Add sleep between retries + HBASE-555 Only one Worker in HRS; on startup, if assigned tens of regions, + havoc of reassignments because open processing is done in series + HBASE-547 UI shows hadoop version, not hbase version + HBASE-561 HBase package does not include LICENSE.txt nor build.xml + HBASE-556 Add 0.16.2 to hbase branch -- if it works + HBASE-563 TestRowFilterAfterWrite erroneously sets master address to + 0.0.0.0:60100 rather than relying on conf + HBASE-554 filters generate StackOverflowException (Clint Morgan via + Jim Kellerman) + HBASE-567 Reused BatchUpdate instances accumulate BatchOperations + + NEW FEATURES + HBASE-548 Tool to online single region + +Release 0.1.0 + + INCOMPATIBLE CHANGES + HADOOP-2750 Deprecated methods startBatchUpdate, commitBatch, abortBatch, + and renewLease have been removed from HTable (Bryan Duxbury via + Jim Kellerman) + HADOOP-2786 Move hbase out of hadoop core + HBASE-403 Fix build after move of hbase in svn + HBASE-494 Up IPC version on 0.1 branch so we cannot mistakenly connect + with a hbase from 0.16.0 + + NEW FEATURES + HBASE-506 When an exception has to escape ServerCallable due to exhausted retries, + show all the exceptions that lead to this situation + + OPTIMIZATIONS + + BUG FIXES + HADOOP-2731 Under load, regions become extremely large and eventually cause + region servers to become unresponsive + HADOOP-2693 NPE in getClosestRowBefore (Bryan Duxbury & Stack) + HADOOP-2599 Some minor improvements to changes in HADOOP-2443 + (Bryan Duxbury & Stack) + HADOOP-2773 Master marks region offline when it is recovering from a region + server death + HBASE-425 Fix doc. so it accomodates new hbase untethered context + HBase-421 TestRegionServerExit broken + HBASE-426 hbase can't find remote filesystem + HBASE-446 Fully qualified hbase.rootdir doesn't work + HBASE-428 Under continuous upload of rows, WrongRegionExceptions are + thrown that reach the client even after retries + HBASE-490 Doubly-assigned .META.; master uses one and clients another + HBASE-496 impossible state for createLease writes 400k lines in about 15mins + HBASE-472 Passing on edits, we dump all to log + HBASE-79 When HBase needs to be migrated, it should display a message on + stdout, not just in the logs + HBASE-495 No server address listed in .META. + HBASE-433 HBASE-251 Region server should delete restore log after successful + restore, Stuck replaying the edits of crashed machine. + HBASE-27 hregioninfo cell empty in meta table + HBASE-501 Empty region server address in info:server entry and a + startcode of -1 in .META. + HBASE-516 HStoreFile.finalKey does not update the final key if it is not + the top region of a split region + HBASE-524 Problems with getFull + HBASE-514 table 'does not exist' when it does + HBASE-537 Wait for hdfs to exit safe mode + HBASE-534 Double-assignment at SPLIT-time + + IMPROVEMENTS + HADOOP-2555 Refactor the HTable#get and HTable#getRow methods to avoid + repetition of retry-on-failure logic (thanks to Peter Dolan and + Bryan Duxbury) + HBASE-281 Shell should allow deletions in .META. and -ROOT- tables + HBASE-480 Tool to manually merge two regions + HBASE-477 Add support for an HBASE_CLASSPATH + HBASE-515 At least double default timeouts between regionserver and master + HBASE-482 package-level javadoc should have example client or at least + point at the FAQ + HBASE-497 RegionServer needs to recover if datanode goes down + HBASE-456 Clearly state which ports need to be opened in order to run HBase + HBASE-483 Merge tool won't merge two overlapping regions + HBASE-476 RegexpRowFilter behaves incorectly when there are multiple store + files (Clint Morgan via Jim Kellerman) + HBASE-527 RegexpRowFilter does not work when there are columns from + multiple families (Clint Morgan via Jim Kellerman) + +Release 0.16.0 + + 2008/02/04 HBase is now a subproject of Hadoop. The first HBase release as + a subproject will be release 0.1.0 which will be equivalent to + the version of HBase included in Hadoop 0.16.0. In order to + accomplish this, the HBase portion of HBASE-288 (formerly + HADOOP-1398) has been backed out. Once 0.1.0 is frozen (depending + mostly on changes to infrastructure due to becoming a sub project + instead of a contrib project), this patch will re-appear on HBase + trunk. + + INCOMPATIBLE CHANGES + HADOOP-2056 A table with row keys containing colon fails to split regions + HADOOP-2079 Fix generated HLog, HRegion names + HADOOP-2495 Minor performance improvements: Slim-down BatchOperation, etc. + HADOOP-2506 Remove the algebra package + HADOOP-2519 Performance improvements: Customized RPC serialization + HADOOP-2478 Restructure how HBase lays out files in the file system (phase 1) + (test input data) + HADOOP-2478 Restructure how HBase lays out files in the file system (phase 2) + Includes migration tool org.apache.hadoop.hbase.util.Migrate + HADOOP-2558 org.onelab.filter.BloomFilter class uses 8X the memory it should + be using + + NEW FEATURES + HADOOP-2061 Add new Base64 dialects + HADOOP-2084 Add a LocalHBaseCluster + HADOOP-2068 RESTful interface (Bryan Duxbury via Stack) + HADOOP-2316 Run REST servlet outside of master + (Bryan Duxbury & Stack) + HADOOP-1550 No means of deleting a'row' (Bryan Duxbuery via Stack) + HADOOP-2384 Delete all members of a column family on a specific row + (Bryan Duxbury via Stack) + HADOOP-2395 Implement "ALTER TABLE ... CHANGE column" operation + (Bryan Duxbury via Stack) + HADOOP-2240 Truncate for hbase (Edward Yoon via Stack) + HADOOP-2389 Provide multiple language bindings for HBase (Thrift) + (David Simpson via Stack) + + OPTIMIZATIONS + HADOOP-2479 Save on number of Text object creations + HADOOP-2485 Make mapfile index interval configurable (Set default to 32 + instead of 128) + HADOOP-2553 Don't make Long objects calculating hbase type hash codes + HADOOP-2377 Holding open MapFile.Readers is expensive, so use less of them + HADOOP-2407 Keeping MapFile.Reader open is expensive: Part 2 + HADOOP-2533 Performance: Scanning, just creating MapWritable in next + consumes >20% CPU + HADOOP-2443 Keep lazy cache of regions in client rather than an + 'authoritative' list (Bryan Duxbury via Stack) + HADOOP-2600 Performance: HStore.getRowKeyAtOrBefore should use + MapFile.Reader#getClosest (before) + (Bryan Duxbury via Stack) + + BUG FIXES + HADOOP-2059 In tests, exceptions in min dfs shutdown should not fail test + (e.g. nightly #272) + HADOOP-2064 TestSplit assertion and NPE failures (Patch build #952 and #953) + HADOOP-2124 Use of `hostname` does not work on Cygwin in some cases + HADOOP-2083 TestTableIndex failed in #970 and #956 + HADOOP-2109 Fixed race condition in processing server lease timeout. + HADOOP-2137 hql.jsp : The character 0x19 is not valid + HADOOP-2109 Fix another race condition in processing dead servers, + Fix error online meta regions: was using region name and not + startKey as key for map.put. Change TestRegionServerExit to + always kill the region server for the META region. This makes + the test more deterministic and getting META reassigned was + problematic. + HADOOP-2155 Method expecting HBaseConfiguration throws NPE when given Configuration + HADOOP-2156 BufferUnderflowException for un-named HTableDescriptors + HADOOP-2161 getRow() is orders of magnitudes slower than get(), even on rows + with one column (Clint Morgan and Stack) + HADOOP-2040 Hudson hangs AFTER test has finished + HADOOP-2274 Excess synchronization introduced by HADOOP-2139 negatively + impacts performance + HADOOP-2196 Fix how hbase sits in hadoop 'package' product + HADOOP-2276 Address regression caused by HADOOP-2274, fix HADOOP-2173 (When + the master times out a region servers lease, the region server + may not restart) + HADOOP-2253 getRow can return HBASE::DELETEVAL cells + (Bryan Duxbury via Stack) + HADOOP-2295 Fix assigning a region to multiple servers + HADOOP-2234 TableInputFormat erroneously aggregates map values + HADOOP-2308 null regioninfo breaks meta scanner + HADOOP-2304 Abbreviated symbol parsing error of dir path in jar command + (Edward Yoon via Stack) + HADOOP-2320 Committed TestGet2 is managled (breaks build). + HADOOP-2322 getRow(row, TS) client interface not properly connected + HADOOP-2309 ConcurrentModificationException doing get of all region start keys + HADOOP-2321 TestScanner2 does not release resources which sometimes cause the + test to time out + HADOOP-2315 REST servlet doesn't treat / characters in row key correctly + (Bryan Duxbury via Stack) + HADOOP-2332 Meta table data selection in Hbase Shell + (Edward Yoon via Stack) + HADOOP-2347 REST servlet not thread safe but run in a threaded manner + (Bryan Duxbury via Stack) + HADOOP-2365 Result of HashFunction.hash() contains all identical values + HADOOP-2362 Leaking hdfs file handle on region split + HADOOP-2338 Fix NullPointerException in master server. + HADOOP-2380 REST servlet throws NPE when any value node has an empty string + (Bryan Duxbury via Stack) + HADOOP-2350 Scanner api returns null row names, or skips row names if + different column families do not have entries for some rows + HADOOP-2283 AlreadyBeingCreatedException (Was: Stuck replay of failed + regionserver edits) + HADOOP-2392 TestRegionServerExit has new failure mode since HADOOP-2338 + HADOOP-2324 Fix assertion failures in TestTableMapReduce + HADOOP-2396 NPE in HMaster.cancelLease + HADOOP-2397 The only time that a meta scanner should try to recover a log is + when the master is starting + HADOOP-2417 Fix critical shutdown problem introduced by HADOOP-2338 + HADOOP-2418 Fix assertion failures in TestTableMapReduce, TestTableIndex, + and TestTableJoinMapReduce + HADOOP-2414 Fix ArrayIndexOutOfBoundsException in bloom filters. + HADOOP-2430 Master will not shut down if there are no active region servers + HADOOP-2199 Add tools for going from hregion filename to region name in logs + HADOOP-2441 Fix build failures in TestHBaseCluster + HADOOP-2451 End key is incorrectly assigned in many region splits + HADOOP-2455 Error in Help-string of CREATE command (Edward Yoon via Stack) + HADOOP-2465 When split parent regions are cleaned up, not all the columns are + deleted + HADOOP-2468 TestRegionServerExit failed in Hadoop-Nightly #338 + HADOOP-2467 scanner truncates resultset when > 1 column families + HADOOP-2503 REST Insert / Select encoding issue (Bryan Duxbury via Stack) + HADOOP-2505 formatter classes missing apache license + HADOOP-2504 REST servlet method for deleting a scanner was not properly + mapped (Bryan Duxbury via Stack) + HADOOP-2507 REST servlet does not properly base64 row keys and column names + (Bryan Duxbury via Stack) + HADOOP-2530 Missing type in new hbase custom RPC serializer + HADOOP-2490 Failure in nightly #346 (Added debugging of hudson failures). + HADOOP-2558 fixes for build up on hudson (part 1, part 2, part 3, part 4) + HADOOP-2500 Unreadable region kills region servers + HADOOP-2579 Initializing a new HTable object against a nonexistent table + throws a NoServerForRegionException instead of a + TableNotFoundException when a different table has been created + previously (Bryan Duxbury via Stack) + HADOOP-2587 Splits blocked by compactions cause region to be offline for + duration of compaction. + HADOOP-2592 Scanning, a region can let out a row that its not supposed + to have + HADOOP-2493 hbase will split on row when the start and end row is the + same cause data loss (Bryan Duxbury via Stack) + HADOOP-2629 Shell digests garbage without complaint + HADOOP-2619 Compaction errors after a region splits + HADOOP-2621 Memcache flush flushing every 60 secs with out considering + the max memcache size + HADOOP-2584 Web UI displays an IOException instead of the Tables + HADOOP-2650 Remove Writables.clone and use WritableUtils.clone from + hadoop instead + HADOOP-2668 Documentation and improved logging so fact that hbase now + requires migration comes as less of a surprise + HADOOP-2686 Removed tables stick around in .META. + HADOOP-2688 IllegalArgumentException processing a shutdown stops + server going down and results in millions of lines of output + HADOOP-2706 HBase Shell crash + HADOOP-2712 under load, regions won't split + HADOOP-2675 Options not passed to rest/thrift + HADOOP-2722 Prevent unintentional thread exit in region server and master + HADOOP-2718 Copy Constructor HBaseConfiguration(Configuration) will override + hbase configurations if argumant is not an instance of + HBaseConfiguration. + HADOOP-2753 Back out 2718; programmatic config works but hbase*xml conf + is overridden + HADOOP-2718 Copy Constructor HBaseConfiguration(Configuration) will override + hbase configurations if argumant is not an instance of + HBaseConfiguration (Put it back again). + HADOOP-2631 2443 breaks HTable.getStartKeys when there is more than one + table or table you are enumerating isn't the first table + Delete empty file: src/contrib/hbase/src/java/org/apache/hadoop/hbase/mapred/ + TableOutputCollector.java per Nigel Daley + + IMPROVEMENTS + HADOOP-2401 Add convenience put method that takes writable + (Johan Oskarsson via Stack) + HADOOP-2074 Simple switch to enable DEBUG level-logging in hbase + HADOOP-2088 Make hbase runnable in $HADOOP_HOME/build(/contrib/hbase) + HADOOP-2126 Use Bob Jenkins' hash for bloom filters + HADOOP-2157 Make Scanners implement Iterable + HADOOP-2176 Htable.deleteAll documentation is ambiguous + HADOOP-2139 (phase 1) Increase parallelism in region servers. + HADOOP-2267 [Hbase Shell] Change the prompt's title from 'hbase' to 'hql'. + (Edward Yoon via Stack) + HADOOP-2139 (phase 2) Make region server more event driven + HADOOP-2289 Useless efforts of looking for the non-existant table in select + command. + (Edward Yoon via Stack) + HADOOP-2257 Show a total of all requests and regions on the web ui + (Paul Saab via Stack) + HADOOP-2261 HTable.abort no longer throws exception if there is no active update. + HADOOP-2287 Make hbase unit tests take less time to complete. + HADOOP-2262 Retry n times instead of n**2 times. + HADOOP-1608 Relational Algrebra Operators + (Edward Yoon via Stack) + HADOOP-2198 HTable should have method to return table metadata + HADOOP-2296 hbase shell: phantom columns show up from select command + HADOOP-2297 System.exit() Handling in hbase shell jar command + (Edward Yoon via Stack) + HADOOP-2224 Add HTable.getRow(ROW, ts) + (Bryan Duxbury via Stack) + HADOOP-2339 Delete command with no WHERE clause + (Edward Yoon via Stack) + HADOOP-2299 Support inclusive scans (Bryan Duxbury via Stack) + HADOOP-2333 Client side retries happen at the wrong level + HADOOP-2357 Compaction cleanup; less deleting + prevent possible file leaks + HADOOP-2392 TestRegionServerExit has new failure mode since HADOOP-2338 + HADOOP-2370 Allow column families with an unlimited number of versions + (Edward Yoon via Stack) + HADOOP-2047 Add an '--master=X' and '--html' command-line parameters to shell + (Edward Yoon via Stack) + HADOOP-2351 If select command returns no result, it doesn't need to show the + header information (Edward Yoon via Stack) + HADOOP-2285 Add being able to shutdown regionservers (Dennis Kubes via Stack) + HADOOP-2458 HStoreFile.writeSplitInfo should just call + HStoreFile.Reference.write + HADOOP-2471 Add reading/writing MapFile to PerformanceEvaluation suite + HADOOP-2522 Separate MapFile benchmark from PerformanceEvaluation + (Tom White via Stack) + HADOOP-2502 Insert/Select timestamp, Timestamp data type in HQL + (Edward Yoon via Stack) + HADOOP-2450 Show version (and svn revision) in hbase web ui + HADOOP-2472 Range selection using filter (Edward Yoon via Stack) + HADOOP-2548 Make TableMap and TableReduce generic + (Frederik Hedberg via Stack) + HADOOP-2557 Shell count function (Edward Yoon via Stack) + HADOOP-2589 Change an classes/package name from Shell to hql + (Edward Yoon via Stack) + HADOOP-2545 hbase rest server should be started with hbase-daemon.sh + HADOOP-2525 Same 2 lines repeated 11 million times in HMaster log upon + HMaster shutdown + HADOOP-2616 hbase not spliting when the total size of region reaches max + region size * 1.5 + HADOOP-2643 Make migration tool smarter. + +Release 0.15.1 +Branch 0.15 + + INCOMPATIBLE CHANGES + HADOOP-1931 Hbase scripts take --ARG=ARG_VALUE when should be like hadoop + and do ---ARG ARG_VALUE + + NEW FEATURES + HADOOP-1768 FS command using Hadoop FsShell operations + (Edward Yoon via Stack) + HADOOP-1784 Delete: Fix scanners and gets so they work properly in presence + of deletes. Added a deleteAll to remove all cells equal to or + older than passed timestamp. Fixed compaction so deleted cells + do not make it out into compacted output. Ensure also that + versions > column max are dropped compacting. + HADOOP-1720 Addition of HQL (Hbase Query Language) support in Hbase Shell. + The old shell syntax has been replaced by HQL, a small SQL-like + set of operators, for creating, altering, dropping, inserting, + deleting, and selecting, etc., data in hbase. + (Inchul Song and Edward Yoon via Stack) + HADOOP-1913 Build a Lucene index on an HBase table + (Ning Li via Stack) + HADOOP-1957 Web UI with report on cluster state and basic browsing of tables + + OPTIMIZATIONS + + BUG FIXES + HADOOP-1527 Region server won't start because logdir exists + HADOOP-1723 If master asks region server to shut down, by-pass return of + shutdown message + HADOOP-1729 Recent renaming or META tables breaks hbase shell + HADOOP-1730 unexpected null value causes META scanner to exit (silently) + HADOOP-1747 On a cluster, on restart, regions multiply assigned + HADOOP-1776 Fix for sporadic compaction failures closing and moving + compaction result + HADOOP-1780 Regions are still being doubly assigned + HADOOP-1797 Fix NPEs in MetaScanner constructor + HADOOP-1799 Incorrect classpath in binary version of Hadoop + HADOOP-1805 Region server hang on exit + HADOOP-1785 TableInputFormat.TableRecordReader.next has a bug + (Ning Li via Stack) + HADOOP-1800 output should default utf8 encoding + HADOOP-1801 When hdfs is yanked out from under hbase, hbase should go down gracefully + HADOOP-1813 OOME makes zombie of region server + HADOOP-1814 TestCleanRegionServerExit fails too often on Hudson + HADOOP-1820 Regionserver creates hlogs without bound + (reverted 2007/09/25) (Fixed 2007/09/30) + HADOOP-1821 Replace all String.getBytes() with String.getBytes("UTF-8") + HADOOP-1832 listTables() returns duplicate tables + HADOOP-1834 Scanners ignore timestamp passed on creation + HADOOP-1847 Many HBase tests do not fail well. + HADOOP-1847 Many HBase tests do not fail well. (phase 2) + HADOOP-1870 Once file system failure has been detected, don't check it again + and get on with shutting down the hbase cluster. + HADOOP-1888 NullPointerException in HMemcacheScanner (reprise) + HADOOP-1903 Possible data loss if Exception happens between snapshot and + flush to disk. + HADOOP-1920 Wrapper scripts broken when hadoop in one location and hbase in + another + HADOOP-1923, HADOOP-1924 a) tests fail sporadically because set up and tear + down is inconsistent b) TestDFSAbort failed in nightly #242 + HADOOP-1929 Add hbase-default.xml to hbase jar + HADOOP-1941 StopRowFilter throws NPE when passed null row + HADOOP-1966 Make HBase unit tests more reliable in the Hudson environment. + HADOOP-1975 HBase tests failing with java.lang.NumberFormatException + HADOOP-1990 Regression test instability affects nightly and patch builds + HADOOP-1996 TestHStoreFile fails on windows if run multiple times + HADOOP-1937 When the master times out a region server's lease, it is too + aggressive in reclaiming the server's log. + HADOOP-2004 webapp hql formatting bugs + HADOOP_2011 Make hbase daemon scripts take args in same order as hadoop + daemon scripts + HADOOP-2017 TestRegionServerAbort failure in patch build #903 and + nightly #266 + HADOOP-2029 TestLogRolling fails too often in patch and nightlies + HADOOP-2038 TestCleanRegionExit failed in patch build #927 + + IMPROVEMENTS + HADOOP-1737 Make HColumnDescriptor data publically members settable + HADOOP-1746 Clean up findbugs warnings + HADOOP-1757 Bloomfilters: single argument constructor, use enum for bloom + filter types + HADOOP-1760 Use new MapWritable and SortedMapWritable classes from + org.apache.hadoop.io + HADOOP-1793 (Phase 1) Remove TestHClient (Phase2) remove HClient. + HADOOP-1794 Remove deprecated APIs + HADOOP-1802 Startup scripts should wait until hdfs as cleared 'safe mode' + HADOOP-1833 bin/stop_hbase.sh returns before it completes + (Izaak Rubin via Stack) + HADOOP-1835 Updated Documentation for HBase setup/installation + (Izaak Rubin via Stack) + HADOOP-1868 Make default configuration more responsive + HADOOP-1884 Remove useless debugging log messages from hbase.mapred + HADOOP-1856 Add Jar command to hbase shell using Hadoop RunJar util + (Edward Yoon via Stack) + HADOOP-1928 Have master pass the regionserver the filesystem to use + HADOOP-1789 Output formatting + HADOOP-1960 If a region server cannot talk to the master before its lease + times out, it should shut itself down + HADOOP-2035 Add logo to webapps + + +Below are the list of changes before 2007-08-18 + + 1. HADOOP-1384. HBase omnibus patch. (jimk, Vuk Ercegovac, and Michael Stack) + 2. HADOOP-1402. Fix javadoc warnings in hbase contrib. (Michael Stack) + 3. HADOOP-1404. HBase command-line shutdown failing (Michael Stack) + 4. HADOOP-1397. Replace custom hbase locking with + java.util.concurrent.locks.ReentrantLock (Michael Stack) + 5. HADOOP-1403. HBase reliability - make master and region server more fault + tolerant. + 6. HADOOP-1418. HBase miscellaneous: unit test for HClient, client to do + 'Performance Evaluation', etc. + 7. HADOOP-1420, HADOOP-1423. Findbugs changes, remove reference to removed + class HLocking. + 8. HADOOP-1424. TestHBaseCluster fails with IllegalMonitorStateException. Fix + regression introduced by HADOOP-1397. + 9. HADOOP-1426. Make hbase scripts executable + add test classes to CLASSPATH. + 10. HADOOP-1430. HBase shutdown leaves regionservers up. + 11. HADOOP-1392. Part1: includes create/delete table; enable/disable table; + add/remove column. + 12. HADOOP-1392. Part2: includes table compaction by merging adjacent regions + that have shrunk in size. + 13. HADOOP-1445 Support updates across region splits and compactions + 14. HADOOP-1460 On shutdown IOException with complaint 'Cannot cancel lease + that is not held' + 15. HADOOP-1421 Failover detection, split log files. + For the files modified, also clean up javadoc, class, field and method + visibility (HADOOP-1466) + 16. HADOOP-1479 Fix NPE in HStore#get if store file only has keys < passed key. + 17. HADOOP-1476 Distributed version of 'Performance Evaluation' script + 18. HADOOP-1469 Asychronous table creation + 19. HADOOP-1415 Integrate BSD licensed bloom filter implementation. + 20. HADOOP-1465 Add cluster stop/start scripts for hbase + 21. HADOOP-1415 Provide configurable per-column bloom filters - part 2. + 22. HADOOP-1498. Replace boxed types with primitives in many places. + 23. HADOOP-1509. Made methods/inner classes in HRegionServer and HClient protected + instead of private for easier extension. Also made HRegion and HRegionInfo public too. + Added an hbase-default.xml property for specifying what HRegionInterface extension to use + for proxy server connection. (James Kennedy via Jim Kellerman) + 24. HADOOP-1534. [hbase] Memcache scanner fails if start key not present + 25. HADOOP-1537. Catch exceptions in testCleanRegionServerExit so we can see + what is failing. + 26. HADOOP-1543 [hbase] Add HClient.tableExists + 27. HADOOP-1519 [hbase] map/reduce interface for HBase. (Vuk Ercegovac and + Jim Kellerman) + 28. HADOOP-1523 Hung region server waiting on write locks + 29. HADOOP-1560 NPE in MiniHBaseCluster on Windows + 30. HADOOP-1531 Add RowFilter to HRegion.HScanner + Adds a row filtering interface and two implemenentations: A page scanner, + and a regex row/column-data matcher. (James Kennedy via Stack) + 31. HADOOP-1566 Key-making utility + 32. HADOOP-1415 Provide configurable per-column bloom filters. + HADOOP-1466 Clean up visibility and javadoc issues in HBase. + 33. HADOOP-1538 Provide capability for client specified time stamps in HBase + HADOOP-1466 Clean up visibility and javadoc issues in HBase. + 34. HADOOP-1589 Exception handling in HBase is broken over client server connections + 35. HADOOP-1375 a simple parser for hbase (Edward Yoon via Stack) + 36. HADOOP-1600 Update license in HBase code + 37. HADOOP-1589 Exception handling in HBase is broken over client server + 38. HADOOP-1574 Concurrent creates of a table named 'X' all succeed + 39. HADOOP-1581 Un-openable tablename bug + 40. HADOOP-1607 [shell] Clear screen command (Edward Yoon via Stack) + 41. HADOOP-1614 [hbase] HClient does not protect itself from simultaneous updates + 42. HADOOP-1468 Add HBase batch update to reduce RPC overhead + 43. HADOOP-1616 Sporadic TestTable failures + 44. HADOOP-1615 Replacing thread notification-based queue with + java.util.concurrent.BlockingQueue in HMaster, HRegionServer + 45. HADOOP-1606 Updated implementation of RowFilterSet, RowFilterInterface + (Izaak Rubin via Stack) + 46. HADOOP-1579 Add new WhileMatchRowFilter and StopRowFilter filters + (Izaak Rubin via Stack) + 47. HADOOP-1637 Fix to HScanner to Support Filters, Add Filter Tests to + TestScanner2 (Izaak Rubin via Stack) + 48. HADOOP-1516 HClient fails to readjust when ROOT or META redeployed on new + region server + 49. HADOOP-1646 RegionServer OOME's under sustained, substantial loading by + 10 concurrent clients + 50. HADOOP-1468 Add HBase batch update to reduce RPC overhead (restrict batches + to a single row at a time) + 51. HADOOP-1528 HClient for multiple tables (phase 1) (James Kennedy & JimK) + 52. HADOOP-1528 HClient for multiple tables (phase 2) all HBase client side code + (except TestHClient and HBaseShell) have been converted to use the new client + side objects (HTable/HBaseAdmin/HConnection) instead of HClient. + 53. HADOOP-1528 HClient for multiple tables - expose close table function + 54. HADOOP-1466 Clean up warnings, visibility and javadoc issues in HBase. + 55. HADOOP-1662 Make region splits faster + 56. HADOOP-1678 On region split, master should designate which host should + serve daughter splits. Phase 1: Master balances load for new regions and + when a region server fails. + 57. HADOOP-1678 On region split, master should designate which host should + serve daughter splits. Phase 2: Master assigns children of split region + instead of HRegionServer serving both children. + 58. HADOOP-1710 All updates should be batch updates + 59. HADOOP-1711 HTable API should use interfaces instead of concrete classes as + method parameters and return values + 60. HADOOP-1644 Compactions should not block updates + 60. HADOOP-1672 HBase Shell should use new client classes + (Edward Yoon via Stack). + 61. HADOOP-1709 Make HRegionInterface more like that of HTable + HADOOP-1725 Client find of table regions should not include offlined, split parents diff --git a/src/java/org/apache/hadoop/hbase/HConstants.java b/src/java/org/apache/hadoop/hbase/HConstants.java index 4c61ccb03b8..c7e89a6dc4a 100644 --- a/src/java/org/apache/hadoop/hbase/HConstants.java +++ b/src/java/org/apache/hadoop/hbase/HConstants.java @@ -1,235 +1,235 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * 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.hadoop.hbase; - -import org.apache.hadoop.hbase.ipc.HRegionInterface; -import org.apache.hadoop.hbase.util.Bytes; - -/** - * HConstants holds a bunch of HBase-related constants - */ -public interface HConstants { - - /** long constant for zero */ - static final Long ZERO_L = Long.valueOf(0L); - - static final String NINES = "99999999999999"; - static final String ZEROES = "00000000000000"; - - // For migration - - /** name of version file */ - static final String VERSION_FILE_NAME = "hbase.version"; - - /** - * Current version of file system - * Version 4 supports only one kind of bloom filter - */ - public static final String FILE_SYSTEM_VERSION = "4"; - - // Configuration parameters - - // TODO: URL for hbase master like hdfs URLs with host and port. - // Like jdbc URLs? URLs could be used to refer to table cells? - // jdbc:mysql://[host][,failoverhost...][:port]/[database] - // jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]... - - // Key into HBaseConfiguration for the hbase.master address. - // TODO: Support 'local': i.e. default of all running in single - // process. Same for regionserver. TODO: Is having HBase homed - // on port 60k OK? - - /** Parameter name for master address */ - static final String MASTER_ADDRESS = "hbase.master"; - - /** default host address */ - static final String DEFAULT_HOST = "0.0.0.0"; - - /** default port that the master listens on */ - static final int DEFAULT_MASTER_PORT = 60000; - - /** Default master address */ - static final String DEFAULT_MASTER_ADDRESS = DEFAULT_HOST + ":" + - DEFAULT_MASTER_PORT; - - /** default port for master web api */ - static final int DEFAULT_MASTER_INFOPORT = 60010; - - /** Parameter name for hbase.regionserver address. */ - static final String REGIONSERVER_ADDRESS = "hbase.regionserver"; - - /** Default region server address */ - static final String DEFAULT_REGIONSERVER_ADDRESS = DEFAULT_HOST + ":60020"; - - /** default port for region server web api */ - static final int DEFAULT_REGIONSERVER_INFOPORT = 60030; - - /** Parameter name for what region server interface to use. */ - static final String REGION_SERVER_CLASS = "hbase.regionserver.class"; - - /** Parameter name for what region server implementation to use. */ - static final String REGION_SERVER_IMPL= "hbase.regionserver.impl"; - - /** Default region server interface class name. */ - static final String DEFAULT_REGION_SERVER_CLASS = HRegionInterface.class.getName(); - - /** Parameter name for how often threads should wake up */ - static final String THREAD_WAKE_FREQUENCY = "hbase.server.thread.wakefrequency"; - - /** Parameter name for HBase instance root directory */ - static final String HBASE_DIR = "hbase.rootdir"; - - /** Used to construct the name of the log directory for a region server */ - static final String HREGION_LOGDIR_NAME = "log"; - - /** Name of old log file for reconstruction */ - static final String HREGION_OLDLOGFILE_NAME = "oldlogfile.log"; - - /** Default maximum file size */ - static final long DEFAULT_MAX_FILE_SIZE = 256 * 1024 * 1024; - - /** Default size of a reservation block */ - static final int DEFAULT_SIZE_RESERVATION_BLOCK = 1024 * 1024 * 5; - - // Always store the location of the root table's HRegion. - // This HRegion is never split. - - // region name = table + startkey + regionid. This is the row key. - // each row in the root and meta tables describes exactly 1 region - // Do we ever need to know all the information that we are storing? - - // Note that the name of the root table starts with "-" and the name of the - // meta table starts with "." Why? it's a trick. It turns out that when we - // store region names in memory, we use a SortedMap. Since "-" sorts before - // "." (and since no other table name can start with either of these - // characters, the root region will always be the first entry in such a Map, - // followed by all the meta regions (which will be ordered by their starting - // row key as well), followed by all user tables. So when the Master is - // choosing regions to assign, it will always choose the root region first, - // followed by the meta regions, followed by user regions. Since the root - // and meta regions always need to be on-line, this ensures that they will - // be the first to be reassigned if the server(s) they are being served by - // should go down. - - /** The root table's name.*/ - static final byte [] ROOT_TABLE_NAME = Bytes.toBytes("-ROOT-"); - - /** The META table's name. */ - static final byte [] META_TABLE_NAME = Bytes.toBytes(".META."); - - // Defines for the column names used in both ROOT and META HBase 'meta' tables. - - /** The ROOT and META column family (string) */ - static final String COLUMN_FAMILY_STR = "info:"; - - /** The META historian column family (string) */ - static final String COLUMN_FAMILY_HISTORIAN_STR = "historian:"; - - /** The ROOT and META column family */ - static final byte [] COLUMN_FAMILY = Bytes.toBytes(COLUMN_FAMILY_STR); - - /** The META historian column family */ - static final byte [] COLUMN_FAMILY_HISTORIAN = Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR); - - /** Array of meta column names */ - static final byte[][] COLUMN_FAMILY_ARRAY = new byte[][] {COLUMN_FAMILY}; - - /** ROOT/META column family member - contains HRegionInfo */ - static final byte [] COL_REGIONINFO = - Bytes.toBytes(COLUMN_FAMILY_STR + "regioninfo"); - - /** Array of column - contains HRegionInfo */ - static final byte[][] COL_REGIONINFO_ARRAY = new byte[][] {COL_REGIONINFO}; - - /** ROOT/META column family member - contains HServerAddress.toString() */ - static final byte[] COL_SERVER = Bytes.toBytes(COLUMN_FAMILY_STR + "server"); - - /** ROOT/META column family member - contains server start code (a long) */ - static final byte [] COL_STARTCODE = - Bytes.toBytes(COLUMN_FAMILY_STR + "serverstartcode"); - - /** the lower half of a split region */ - static final byte [] COL_SPLITA = Bytes.toBytes(COLUMN_FAMILY_STR + "splitA"); - - /** the upper half of a split region */ - static final byte [] COL_SPLITB = Bytes.toBytes(COLUMN_FAMILY_STR + "splitB"); - - /** All the columns in the catalog -ROOT- and .META. tables. - */ - static final byte[][] ALL_META_COLUMNS = {COL_REGIONINFO, COL_SERVER, - COL_STARTCODE, COL_SPLITA, COL_SPLITB}; - - // Other constants - - /** - * An empty instance. - */ - static final byte [] EMPTY_BYTE_ARRAY = new byte [0]; - - /** - * Used by scanners, etc when they want to start at the beginning of a region - */ - static final byte [] EMPTY_START_ROW = EMPTY_BYTE_ARRAY; - - /** - * Last row in a table. - */ - static final byte [] EMPTY_END_ROW = EMPTY_START_ROW; - - /** - * Used by scanners and others when they're trying to detect the end of a - * table - */ - static final byte [] LAST_ROW = EMPTY_BYTE_ARRAY; - - /** When we encode strings, we always specify UTF8 encoding */ - static final String UTF8_ENCODING = "UTF-8"; - - /** - * Timestamp to use when we want to refer to the latest cell. - * This is the timestamp sent by clients when no timestamp is specified on - * commit. - */ - static final long LATEST_TIMESTAMP = Long.MAX_VALUE; - - /** - * Define for 'return-all-versions'. - */ - static final int ALL_VERSIONS = Integer.MAX_VALUE; - - /** - * Unlimited time-to-live. - */ - static final int FOREVER = -1; - - public static final String HBASE_CLIENT_RETRIES_NUMBER_KEY = - "hbase.client.retries.number"; - public static final int DEFAULT_CLIENT_RETRIES = 5; - - public static final String NAME = "NAME"; - public static final String VERSIONS = "VERSIONS"; - public static final String IN_MEMORY = "IN_MEMORY"; - - /** - * This is a retry backoff multiplier table similar to the BSD TCP syn - * backoff table, a bit more aggressive than simple exponential backoff. - */ - public static int RETRY_BACKOFF[] = { 1, 1, 1, 1, 2, 4, 8, 16, 32, 64 }; +/** + * Copyright 2007 The Apache Software Foundation + * + * 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.hadoop.hbase; + +import org.apache.hadoop.hbase.ipc.HRegionInterface; +import org.apache.hadoop.hbase.util.Bytes; + +/** + * HConstants holds a bunch of HBase-related constants + */ +public interface HConstants { + + /** long constant for zero */ + static final Long ZERO_L = Long.valueOf(0L); + + static final String NINES = "99999999999999"; + static final String ZEROES = "00000000000000"; + + // For migration + + /** name of version file */ + static final String VERSION_FILE_NAME = "hbase.version"; + + /** + * Current version of file system + * Version 4 supports only one kind of bloom filter + */ + public static final String FILE_SYSTEM_VERSION = "4"; + + // Configuration parameters + + // TODO: URL for hbase master like hdfs URLs with host and port. + // Like jdbc URLs? URLs could be used to refer to table cells? + // jdbc:mysql://[host][,failoverhost...][:port]/[database] + // jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]... + + // Key into HBaseConfiguration for the hbase.master address. + // TODO: Support 'local': i.e. default of all running in single + // process. Same for regionserver. TODO: Is having HBase homed + // on port 60k OK? + + /** Parameter name for master address */ + static final String MASTER_ADDRESS = "hbase.master"; + + /** default host address */ + static final String DEFAULT_HOST = "0.0.0.0"; + + /** default port that the master listens on */ + static final int DEFAULT_MASTER_PORT = 60000; + + /** Default master address */ + static final String DEFAULT_MASTER_ADDRESS = DEFAULT_HOST + ":" + + DEFAULT_MASTER_PORT; + + /** default port for master web api */ + static final int DEFAULT_MASTER_INFOPORT = 60010; + + /** Parameter name for hbase.regionserver address. */ + static final String REGIONSERVER_ADDRESS = "hbase.regionserver"; + + /** Default region server address */ + static final String DEFAULT_REGIONSERVER_ADDRESS = DEFAULT_HOST + ":60020"; + + /** default port for region server web api */ + static final int DEFAULT_REGIONSERVER_INFOPORT = 60030; + + /** Parameter name for what region server interface to use. */ + static final String REGION_SERVER_CLASS = "hbase.regionserver.class"; + + /** Parameter name for what region server implementation to use. */ + static final String REGION_SERVER_IMPL= "hbase.regionserver.impl"; + + /** Default region server interface class name. */ + static final String DEFAULT_REGION_SERVER_CLASS = HRegionInterface.class.getName(); + + /** Parameter name for how often threads should wake up */ + static final String THREAD_WAKE_FREQUENCY = "hbase.server.thread.wakefrequency"; + + /** Parameter name for HBase instance root directory */ + static final String HBASE_DIR = "hbase.rootdir"; + + /** Used to construct the name of the log directory for a region server */ + static final String HREGION_LOGDIR_NAME = "log"; + + /** Name of old log file for reconstruction */ + static final String HREGION_OLDLOGFILE_NAME = "oldlogfile.log"; + + /** Default maximum file size */ + static final long DEFAULT_MAX_FILE_SIZE = 256 * 1024 * 1024; + + /** Default size of a reservation block */ + static final int DEFAULT_SIZE_RESERVATION_BLOCK = 1024 * 1024 * 5; + + // Always store the location of the root table's HRegion. + // This HRegion is never split. + + // region name = table + startkey + regionid. This is the row key. + // each row in the root and meta tables describes exactly 1 region + // Do we ever need to know all the information that we are storing? + + // Note that the name of the root table starts with "-" and the name of the + // meta table starts with "." Why? it's a trick. It turns out that when we + // store region names in memory, we use a SortedMap. Since "-" sorts before + // "." (and since no other table name can start with either of these + // characters, the root region will always be the first entry in such a Map, + // followed by all the meta regions (which will be ordered by their starting + // row key as well), followed by all user tables. So when the Master is + // choosing regions to assign, it will always choose the root region first, + // followed by the meta regions, followed by user regions. Since the root + // and meta regions always need to be on-line, this ensures that they will + // be the first to be reassigned if the server(s) they are being served by + // should go down. + + /** The root table's name.*/ + static final byte [] ROOT_TABLE_NAME = Bytes.toBytes("-ROOT-"); + + /** The META table's name. */ + static final byte [] META_TABLE_NAME = Bytes.toBytes(".META."); + + // Defines for the column names used in both ROOT and META HBase 'meta' tables. + + /** The ROOT and META column family (string) */ + static final String COLUMN_FAMILY_STR = "info:"; + + /** The META historian column family (string) */ + static final String COLUMN_FAMILY_HISTORIAN_STR = "historian:"; + + /** The ROOT and META column family */ + static final byte [] COLUMN_FAMILY = Bytes.toBytes(COLUMN_FAMILY_STR); + + /** The META historian column family */ + static final byte [] COLUMN_FAMILY_HISTORIAN = Bytes.toBytes(COLUMN_FAMILY_HISTORIAN_STR); + + /** Array of meta column names */ + static final byte[][] COLUMN_FAMILY_ARRAY = new byte[][] {COLUMN_FAMILY}; + + /** ROOT/META column family member - contains HRegionInfo */ + static final byte [] COL_REGIONINFO = + Bytes.toBytes(COLUMN_FAMILY_STR + "regioninfo"); + + /** Array of column - contains HRegionInfo */ + static final byte[][] COL_REGIONINFO_ARRAY = new byte[][] {COL_REGIONINFO}; + + /** ROOT/META column family member - contains HServerAddress.toString() */ + static final byte[] COL_SERVER = Bytes.toBytes(COLUMN_FAMILY_STR + "server"); + + /** ROOT/META column family member - contains server start code (a long) */ + static final byte [] COL_STARTCODE = + Bytes.toBytes(COLUMN_FAMILY_STR + "serverstartcode"); + + /** the lower half of a split region */ + static final byte [] COL_SPLITA = Bytes.toBytes(COLUMN_FAMILY_STR + "splitA"); + + /** the upper half of a split region */ + static final byte [] COL_SPLITB = Bytes.toBytes(COLUMN_FAMILY_STR + "splitB"); + + /** All the columns in the catalog -ROOT- and .META. tables. + */ + static final byte[][] ALL_META_COLUMNS = {COL_REGIONINFO, COL_SERVER, + COL_STARTCODE, COL_SPLITA, COL_SPLITB}; + + // Other constants + + /** + * An empty instance. + */ + static final byte [] EMPTY_BYTE_ARRAY = new byte [0]; + + /** + * Used by scanners, etc when they want to start at the beginning of a region + */ + static final byte [] EMPTY_START_ROW = EMPTY_BYTE_ARRAY; + + /** + * Last row in a table. + */ + static final byte [] EMPTY_END_ROW = EMPTY_START_ROW; + + /** + * Used by scanners and others when they're trying to detect the end of a + * table + */ + static final byte [] LAST_ROW = EMPTY_BYTE_ARRAY; + + /** When we encode strings, we always specify UTF8 encoding */ + static final String UTF8_ENCODING = "UTF-8"; + + /** + * Timestamp to use when we want to refer to the latest cell. + * This is the timestamp sent by clients when no timestamp is specified on + * commit. + */ + static final long LATEST_TIMESTAMP = Long.MAX_VALUE; + + /** + * Define for 'return-all-versions'. + */ + static final int ALL_VERSIONS = Integer.MAX_VALUE; + + /** + * Unlimited time-to-live. + */ + static final int FOREVER = -1; + + public static final String HBASE_CLIENT_RETRIES_NUMBER_KEY = + "hbase.client.retries.number"; + public static final int DEFAULT_CLIENT_RETRIES = 5; + + public static final String NAME = "NAME"; + public static final String VERSIONS = "VERSIONS"; + public static final String IN_MEMORY = "IN_MEMORY"; + + /** + * This is a retry backoff multiplier table similar to the BSD TCP syn + * backoff table, a bit more aggressive than simple exponential backoff. + */ + public static int RETRY_BACKOFF[] = { 1, 1, 1, 1, 2, 4, 8, 16, 32, 64 }; } \ No newline at end of file diff --git a/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index 2561fdc2926..3e94aed9e34 100644 --- a/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/src/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -1,634 +1,634 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * 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.hadoop.hbase.client; - -import java.io.IOException; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.HBaseConfiguration; -import org.apache.hadoop.hbase.HColumnDescriptor; -import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.HRegionInfo; -import org.apache.hadoop.hbase.HRegionLocation; -import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.MasterNotRunningException; -import org.apache.hadoop.hbase.RemoteExceptionHandler; -import org.apache.hadoop.hbase.TableExistsException; -import org.apache.hadoop.hbase.TableNotFoundException; -import org.apache.hadoop.hbase.io.Cell; -import org.apache.hadoop.hbase.io.RowResult; -import org.apache.hadoop.hbase.ipc.HMasterInterface; -import org.apache.hadoop.hbase.ipc.HRegionInterface; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Writables; -import org.apache.hadoop.io.Text; -import org.apache.hadoop.ipc.RemoteException; - -/** - * Provides administrative functions for HBase - */ -public class HBaseAdmin { - private final Log LOG = LogFactory.getLog(this.getClass().getName()); - private final HConnection connection; - private final long pause; - private final int numRetries; - private volatile HMasterInterface master; - - /** - * Constructor - * - * @param conf Configuration object - * @throws MasterNotRunningException - */ - public HBaseAdmin(HBaseConfiguration conf) throws MasterNotRunningException { - this.connection = HConnectionManager.getConnection(conf); - this.pause = conf.getLong("hbase.client.pause", 30 * 1000); - this.numRetries = conf.getInt("hbase.client.retries.number", 5); - this.master = connection.getMaster(); - } - - /** - * @return proxy connection to master server for this instance - * @throws MasterNotRunningException - */ - public HMasterInterface getMaster() throws MasterNotRunningException{ - return this.connection.getMaster(); - } - - /** @return - true if the master server is running */ - public boolean isMasterRunning() { - return this.connection.isMasterRunning(); - } - - /** - * @param tableName Table to check. - * @return True if table exists already. - * @throws MasterNotRunningException - */ - public boolean tableExists(final Text tableName) - throws MasterNotRunningException { - return tableExists(tableName.getBytes()); - } - - /** - * @param tableName Table to check. - * @return True if table exists already. - * @throws MasterNotRunningException - */ - public boolean tableExists(final String tableName) - throws MasterNotRunningException { - return tableExists(Bytes.toBytes(tableName)); - } - - /** - * @param tableName Table to check. - * @return True if table exists already. - * @throws MasterNotRunningException - */ - public boolean tableExists(final byte [] tableName) - throws MasterNotRunningException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - return connection.tableExists(tableName); - } - - /** - * List all the userspace tables. In other words, scan the META table. - * - * If we wanted this to be really fast, we could implement a special - * catalog table that just contains table names and their descriptors. - * Right now, it only exists as part of the META table's region info. - * - * @return - returns an array of HTableDescriptors - * @throws IOException - */ - public HTableDescriptor[] listTables() throws IOException { - return this.connection.listTables(); - } - - private long getPauseTime(int tries) { - if (tries >= HConstants.RETRY_BACKOFF.length) - tries = HConstants.RETRY_BACKOFF.length - 1; - return this.pause * HConstants.RETRY_BACKOFF[tries]; - } - - /** - * Creates a new table - * - * @param desc table descriptor for table - * - * @throws IllegalArgumentException if the table name is reserved - * @throws MasterNotRunningException if master is not running - * @throws TableExistsException if table already exists (If concurrent - * threads, the table may have been created between test-for-existence - * and attempt-at-creation). - * @throws IOException - */ - public void createTable(HTableDescriptor desc) - throws IOException { - HTableDescriptor.isLegalTableName(desc.getName()); - createTableAsync(desc); - for (int tries = 0; tries < numRetries; tries++) { - try { - // Wait for new table to come on-line - connection.locateRegion(desc.getName(), HConstants.EMPTY_START_ROW); - break; - - } catch (TableNotFoundException e) { - if (tries == numRetries - 1) { - // Ran out of tries - throw e; - } - } - try { - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e) { - // continue - } - } - } - - /** - * Creates a new table but does not block and wait for it to come online. - * - * @param desc table descriptor for table - * - * @throws IllegalArgumentException Bad table name. - * @throws MasterNotRunningException if master is not running - * @throws TableExistsException if table already exists (If concurrent - * threads, the table may have been created between test-for-existence - * and attempt-at-creation). - * @throws IOException - */ - public void createTableAsync(HTableDescriptor desc) - throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - HTableDescriptor.isLegalTableName(desc.getName()); - try { - this.master.createTable(desc); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - } - - /** - * Deletes a table - * - * @param tableName name of table to delete - * @throws IOException - */ - public void deleteTable(final Text tableName) throws IOException { - deleteTable(tableName.getBytes()); - } - - /** - * Deletes a table - * - * @param tableName name of table to delete - * @throws IOException - */ - public void deleteTable(final String tableName) throws IOException { - deleteTable(Bytes.toBytes(tableName)); - } - - /** - * Deletes a table - * - * @param tableName name of table to delete - * @throws IOException - */ - public void deleteTable(final byte [] tableName) throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - HTableDescriptor.isLegalTableName(tableName); - HRegionLocation firstMetaServer = getFirstMetaServerForTable(tableName); - try { - this.master.deleteTable(tableName); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - - // Wait until first region is deleted - HRegionInterface server = - connection.getHRegionConnection(firstMetaServer.getServerAddress()); - HRegionInfo info = new HRegionInfo(); - for (int tries = 0; tries < numRetries; tries++) { - long scannerId = -1L; - try { - scannerId = - server.openScanner(firstMetaServer.getRegionInfo().getRegionName(), - HConstants.COL_REGIONINFO_ARRAY, tableName, - HConstants.LATEST_TIMESTAMP, null); - RowResult values = server.next(scannerId); - if (values == null || values.size() == 0) { - break; - } - boolean found = false; - for (Map.Entry e: values.entrySet()) { - if (Bytes.equals(e.getKey(), HConstants.COL_REGIONINFO)) { - info = (HRegionInfo) Writables.getWritable( - e.getValue().getValue(), info); - - if (Bytes.equals(info.getTableDesc().getName(), tableName)) { - found = true; - } - } - } - if (!found) { - break; - } - - } catch (IOException ex) { - if(tries == numRetries - 1) { // no more tries left - if (ex instanceof RemoteException) { - ex = RemoteExceptionHandler.decodeRemoteException((RemoteException) ex); - } - throw ex; - } - - } finally { - if (scannerId != -1L) { - try { - server.close(scannerId); - } catch (Exception ex) { - LOG.warn(ex); - } - } - } - - try { - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e) { - // continue - } - } - LOG.info("Deleted " + Bytes.toString(tableName)); - } - - /** - * Brings a table on-line (enables it) - * - * @param tableName name of the table - * @throws IOException - */ - public void enableTable(final Text tableName) throws IOException { - enableTable(tableName.getBytes()); - } - - /** - * Brings a table on-line (enables it) - * - * @param tableName name of the table - * @throws IOException - */ - public void enableTable(final String tableName) throws IOException { - enableTable(Bytes.toBytes(tableName)); - } - - /** - * Brings a table on-line (enables it) - * - * @param tableName name of the table - * @throws IOException - */ - public void enableTable(final byte [] tableName) throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - try { - this.master.enableTable(tableName); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - - // Wait until all regions are enabled - - for (int tries = 0; - (tries < numRetries) && (!isTableEnabled(tableName)); - tries++) { - if (LOG.isDebugEnabled()) { - LOG.debug("Sleep. Waiting for all regions to be enabled from " + - Bytes.toString(tableName)); - } - try { - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e) { - // continue - } - if (LOG.isDebugEnabled()) { - LOG.debug("Wake. Waiting for all regions to be enabled from " + - Bytes.toString(tableName)); - } - } - if (!isTableEnabled(tableName)) - throw new IOException("unable to enable table " + - Bytes.toString(tableName)); - LOG.info("Enabled table " + Bytes.toString(tableName)); - } - - /** - * Disables a table (takes it off-line) If it is being served, the master - * will tell the servers to stop serving it. - * - * @param tableName name of table - * @throws IOException - */ - public void disableTable(final Text tableName) throws IOException { - disableTable(tableName.getBytes()); - } - - /** - * Disables a table (takes it off-line) If it is being served, the master - * will tell the servers to stop serving it. - * - * @param tableName name of table - * @throws IOException - */ - public void disableTable(final String tableName) throws IOException { - disableTable(Bytes.toBytes(tableName)); - } - - /** - * Disables a table (takes it off-line) If it is being served, the master - * will tell the servers to stop serving it. - * - * @param tableName name of table - * @throws IOException - */ - public void disableTable(final byte [] tableName) throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - try { - this.master.disableTable(tableName); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - - // Wait until all regions are disabled - for (int tries = 0; - (tries < numRetries) && (isTableEnabled(tableName)); - tries++) { - if (LOG.isDebugEnabled()) { - LOG.debug("Sleep. Waiting for all regions to be disabled from " + - Bytes.toString(tableName)); - } - try { - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e) { - // continue - } - if (LOG.isDebugEnabled()) { - LOG.debug("Wake. Waiting for all regions to be disabled from " + - Bytes.toString(tableName)); - } - } - if (isTableEnabled(tableName)) - throw new IOException("unable to disable table " + - Bytes.toString(tableName)); - LOG.info("Disabled " + Bytes.toString(tableName)); - } - - /** - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public boolean isTableEnabled(Text tableName) throws IOException { - return isTableEnabled(tableName.getBytes()); - } - /** - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public boolean isTableEnabled(String tableName) throws IOException { - return isTableEnabled(Bytes.toBytes(tableName)); - } - /** - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public boolean isTableEnabled(byte[] tableName) throws IOException { - return connection.isTableEnabled(tableName); - } - - /** - * Add a column to an existing table - * - * @param tableName name of the table to add column to - * @param column column descriptor of column to be added - * @throws IOException - */ - public void addColumn(final Text tableName, HColumnDescriptor column) - throws IOException { - addColumn(tableName.getBytes(), column); - } - - /** - * Add a column to an existing table - * - * @param tableName name of the table to add column to - * @param column column descriptor of column to be added - * @throws IOException - */ - public void addColumn(final String tableName, HColumnDescriptor column) - throws IOException { - addColumn(Bytes.toBytes(tableName), column); - } - - /** - * Add a column to an existing table - * - * @param tableName name of the table to add column to - * @param column column descriptor of column to be added - * @throws IOException - */ - public void addColumn(final byte [] tableName, HColumnDescriptor column) - throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - HTableDescriptor.isLegalTableName(tableName); - try { - this.master.addColumn(tableName, column); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - } - - /** - * Delete a column from a table - * - * @param tableName name of table - * @param columnName name of column to be deleted - * @throws IOException - */ - public void deleteColumn(final Text tableName, final Text columnName) - throws IOException { - deleteColumn(tableName.getBytes(), columnName.getBytes()); - } - - /** - * Delete a column from a table - * - * @param tableName name of table - * @param columnName name of column to be deleted - * @throws IOException - */ - public void deleteColumn(final String tableName, final String columnName) - throws IOException { - deleteColumn(Bytes.toBytes(tableName), Bytes.toBytes(columnName)); - } - - /** - * Delete a column from a table - * - * @param tableName name of table - * @param columnName name of column to be deleted - * @throws IOException - */ - public void deleteColumn(final byte [] tableName, final byte [] columnName) - throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - HTableDescriptor.isLegalTableName(tableName); - try { - this.master.deleteColumn(tableName, columnName); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - } - - /** - * Modify an existing column family on a table - * - * @param tableName name of table - * @param columnName name of column to be modified - * @param descriptor new column descriptor to use - * @throws IOException - */ - public void modifyColumn(final Text tableName, final Text columnName, - HColumnDescriptor descriptor) - throws IOException { - modifyColumn(tableName.getBytes(), columnName.getBytes(), descriptor); - } - - /** - * Modify an existing column family on a table - * - * @param tableName name of table - * @param columnName name of column to be modified - * @param descriptor new column descriptor to use - * @throws IOException - */ - public void modifyColumn(final String tableName, final String columnName, - HColumnDescriptor descriptor) - throws IOException { - modifyColumn(Bytes.toBytes(tableName), Bytes.toBytes(columnName), - descriptor); - } - - /** - * Modify an existing column family on a table - * - * @param tableName name of table - * @param columnName name of column to be modified - * @param descriptor new column descriptor to use - * @throws IOException - */ - public void modifyColumn(final byte [] tableName, final byte [] columnName, - HColumnDescriptor descriptor) - throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - HTableDescriptor.isLegalTableName(tableName); - try { - this.master.modifyColumn(tableName, columnName, descriptor); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - } - - /** - * Modify a table's HTableDescriptor - * - * @param tableName name of table - * @param desc the updated descriptor - * @throws IOException - */ - public void modifyTableMeta(final byte [] tableName, HTableDescriptor desc) - throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - HTableDescriptor.isLegalTableName(tableName); - try { - this.master.modifyTableMeta(tableName, desc); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - } - - /** - * Shuts down the HBase instance - * @throws IOException - */ - public synchronized void shutdown() throws IOException { - if (this.master == null) { - throw new MasterNotRunningException("master has been shut down"); - } - try { - this.master.shutdown(); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } finally { - this.master = null; - } - } - - private HRegionLocation getFirstMetaServerForTable(final byte [] tableName) - throws IOException { - return connection.locateRegion(HConstants.META_TABLE_NAME, - HRegionInfo.createRegionName(tableName, null, HConstants.NINES)); - } - - /** - * Check to see if HBase is running. Throw an exception if not. - * - * @param conf - * @throws MasterNotRunningException - */ - public static void checkHBaseAvailable(HBaseConfiguration conf) - throws MasterNotRunningException { - HBaseConfiguration copyOfConf = new HBaseConfiguration(conf); - copyOfConf.setInt("hbase.client.retries.number", 1); - new HBaseAdmin(copyOfConf); - } +/** + * Copyright 2007 The Apache Software Foundation + * + * 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.hadoop.hbase.client; + +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HRegionLocation; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.MasterNotRunningException; +import org.apache.hadoop.hbase.RemoteExceptionHandler; +import org.apache.hadoop.hbase.TableExistsException; +import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.io.Cell; +import org.apache.hadoop.hbase.io.RowResult; +import org.apache.hadoop.hbase.ipc.HMasterInterface; +import org.apache.hadoop.hbase.ipc.HRegionInterface; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Writables; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.ipc.RemoteException; + +/** + * Provides administrative functions for HBase + */ +public class HBaseAdmin { + private final Log LOG = LogFactory.getLog(this.getClass().getName()); + private final HConnection connection; + private final long pause; + private final int numRetries; + private volatile HMasterInterface master; + + /** + * Constructor + * + * @param conf Configuration object + * @throws MasterNotRunningException + */ + public HBaseAdmin(HBaseConfiguration conf) throws MasterNotRunningException { + this.connection = HConnectionManager.getConnection(conf); + this.pause = conf.getLong("hbase.client.pause", 30 * 1000); + this.numRetries = conf.getInt("hbase.client.retries.number", 5); + this.master = connection.getMaster(); + } + + /** + * @return proxy connection to master server for this instance + * @throws MasterNotRunningException + */ + public HMasterInterface getMaster() throws MasterNotRunningException{ + return this.connection.getMaster(); + } + + /** @return - true if the master server is running */ + public boolean isMasterRunning() { + return this.connection.isMasterRunning(); + } + + /** + * @param tableName Table to check. + * @return True if table exists already. + * @throws MasterNotRunningException + */ + public boolean tableExists(final Text tableName) + throws MasterNotRunningException { + return tableExists(tableName.getBytes()); + } + + /** + * @param tableName Table to check. + * @return True if table exists already. + * @throws MasterNotRunningException + */ + public boolean tableExists(final String tableName) + throws MasterNotRunningException { + return tableExists(Bytes.toBytes(tableName)); + } + + /** + * @param tableName Table to check. + * @return True if table exists already. + * @throws MasterNotRunningException + */ + public boolean tableExists(final byte [] tableName) + throws MasterNotRunningException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + return connection.tableExists(tableName); + } + + /** + * List all the userspace tables. In other words, scan the META table. + * + * If we wanted this to be really fast, we could implement a special + * catalog table that just contains table names and their descriptors. + * Right now, it only exists as part of the META table's region info. + * + * @return - returns an array of HTableDescriptors + * @throws IOException + */ + public HTableDescriptor[] listTables() throws IOException { + return this.connection.listTables(); + } + + private long getPauseTime(int tries) { + if (tries >= HConstants.RETRY_BACKOFF.length) + tries = HConstants.RETRY_BACKOFF.length - 1; + return this.pause * HConstants.RETRY_BACKOFF[tries]; + } + + /** + * Creates a new table + * + * @param desc table descriptor for table + * + * @throws IllegalArgumentException if the table name is reserved + * @throws MasterNotRunningException if master is not running + * @throws TableExistsException if table already exists (If concurrent + * threads, the table may have been created between test-for-existence + * and attempt-at-creation). + * @throws IOException + */ + public void createTable(HTableDescriptor desc) + throws IOException { + HTableDescriptor.isLegalTableName(desc.getName()); + createTableAsync(desc); + for (int tries = 0; tries < numRetries; tries++) { + try { + // Wait for new table to come on-line + connection.locateRegion(desc.getName(), HConstants.EMPTY_START_ROW); + break; + + } catch (TableNotFoundException e) { + if (tries == numRetries - 1) { + // Ran out of tries + throw e; + } + } + try { + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e) { + // continue + } + } + } + + /** + * Creates a new table but does not block and wait for it to come online. + * + * @param desc table descriptor for table + * + * @throws IllegalArgumentException Bad table name. + * @throws MasterNotRunningException if master is not running + * @throws TableExistsException if table already exists (If concurrent + * threads, the table may have been created between test-for-existence + * and attempt-at-creation). + * @throws IOException + */ + public void createTableAsync(HTableDescriptor desc) + throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + HTableDescriptor.isLegalTableName(desc.getName()); + try { + this.master.createTable(desc); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + } + + /** + * Deletes a table + * + * @param tableName name of table to delete + * @throws IOException + */ + public void deleteTable(final Text tableName) throws IOException { + deleteTable(tableName.getBytes()); + } + + /** + * Deletes a table + * + * @param tableName name of table to delete + * @throws IOException + */ + public void deleteTable(final String tableName) throws IOException { + deleteTable(Bytes.toBytes(tableName)); + } + + /** + * Deletes a table + * + * @param tableName name of table to delete + * @throws IOException + */ + public void deleteTable(final byte [] tableName) throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + HTableDescriptor.isLegalTableName(tableName); + HRegionLocation firstMetaServer = getFirstMetaServerForTable(tableName); + try { + this.master.deleteTable(tableName); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + + // Wait until first region is deleted + HRegionInterface server = + connection.getHRegionConnection(firstMetaServer.getServerAddress()); + HRegionInfo info = new HRegionInfo(); + for (int tries = 0; tries < numRetries; tries++) { + long scannerId = -1L; + try { + scannerId = + server.openScanner(firstMetaServer.getRegionInfo().getRegionName(), + HConstants.COL_REGIONINFO_ARRAY, tableName, + HConstants.LATEST_TIMESTAMP, null); + RowResult values = server.next(scannerId); + if (values == null || values.size() == 0) { + break; + } + boolean found = false; + for (Map.Entry e: values.entrySet()) { + if (Bytes.equals(e.getKey(), HConstants.COL_REGIONINFO)) { + info = (HRegionInfo) Writables.getWritable( + e.getValue().getValue(), info); + + if (Bytes.equals(info.getTableDesc().getName(), tableName)) { + found = true; + } + } + } + if (!found) { + break; + } + + } catch (IOException ex) { + if(tries == numRetries - 1) { // no more tries left + if (ex instanceof RemoteException) { + ex = RemoteExceptionHandler.decodeRemoteException((RemoteException) ex); + } + throw ex; + } + + } finally { + if (scannerId != -1L) { + try { + server.close(scannerId); + } catch (Exception ex) { + LOG.warn(ex); + } + } + } + + try { + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e) { + // continue + } + } + LOG.info("Deleted " + Bytes.toString(tableName)); + } + + /** + * Brings a table on-line (enables it) + * + * @param tableName name of the table + * @throws IOException + */ + public void enableTable(final Text tableName) throws IOException { + enableTable(tableName.getBytes()); + } + + /** + * Brings a table on-line (enables it) + * + * @param tableName name of the table + * @throws IOException + */ + public void enableTable(final String tableName) throws IOException { + enableTable(Bytes.toBytes(tableName)); + } + + /** + * Brings a table on-line (enables it) + * + * @param tableName name of the table + * @throws IOException + */ + public void enableTable(final byte [] tableName) throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + try { + this.master.enableTable(tableName); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + + // Wait until all regions are enabled + + for (int tries = 0; + (tries < numRetries) && (!isTableEnabled(tableName)); + tries++) { + if (LOG.isDebugEnabled()) { + LOG.debug("Sleep. Waiting for all regions to be enabled from " + + Bytes.toString(tableName)); + } + try { + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e) { + // continue + } + if (LOG.isDebugEnabled()) { + LOG.debug("Wake. Waiting for all regions to be enabled from " + + Bytes.toString(tableName)); + } + } + if (!isTableEnabled(tableName)) + throw new IOException("unable to enable table " + + Bytes.toString(tableName)); + LOG.info("Enabled table " + Bytes.toString(tableName)); + } + + /** + * Disables a table (takes it off-line) If it is being served, the master + * will tell the servers to stop serving it. + * + * @param tableName name of table + * @throws IOException + */ + public void disableTable(final Text tableName) throws IOException { + disableTable(tableName.getBytes()); + } + + /** + * Disables a table (takes it off-line) If it is being served, the master + * will tell the servers to stop serving it. + * + * @param tableName name of table + * @throws IOException + */ + public void disableTable(final String tableName) throws IOException { + disableTable(Bytes.toBytes(tableName)); + } + + /** + * Disables a table (takes it off-line) If it is being served, the master + * will tell the servers to stop serving it. + * + * @param tableName name of table + * @throws IOException + */ + public void disableTable(final byte [] tableName) throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + try { + this.master.disableTable(tableName); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + + // Wait until all regions are disabled + for (int tries = 0; + (tries < numRetries) && (isTableEnabled(tableName)); + tries++) { + if (LOG.isDebugEnabled()) { + LOG.debug("Sleep. Waiting for all regions to be disabled from " + + Bytes.toString(tableName)); + } + try { + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e) { + // continue + } + if (LOG.isDebugEnabled()) { + LOG.debug("Wake. Waiting for all regions to be disabled from " + + Bytes.toString(tableName)); + } + } + if (isTableEnabled(tableName)) + throw new IOException("unable to disable table " + + Bytes.toString(tableName)); + LOG.info("Disabled " + Bytes.toString(tableName)); + } + + /** + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public boolean isTableEnabled(Text tableName) throws IOException { + return isTableEnabled(tableName.getBytes()); + } + /** + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public boolean isTableEnabled(String tableName) throws IOException { + return isTableEnabled(Bytes.toBytes(tableName)); + } + /** + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public boolean isTableEnabled(byte[] tableName) throws IOException { + return connection.isTableEnabled(tableName); + } + + /** + * Add a column to an existing table + * + * @param tableName name of the table to add column to + * @param column column descriptor of column to be added + * @throws IOException + */ + public void addColumn(final Text tableName, HColumnDescriptor column) + throws IOException { + addColumn(tableName.getBytes(), column); + } + + /** + * Add a column to an existing table + * + * @param tableName name of the table to add column to + * @param column column descriptor of column to be added + * @throws IOException + */ + public void addColumn(final String tableName, HColumnDescriptor column) + throws IOException { + addColumn(Bytes.toBytes(tableName), column); + } + + /** + * Add a column to an existing table + * + * @param tableName name of the table to add column to + * @param column column descriptor of column to be added + * @throws IOException + */ + public void addColumn(final byte [] tableName, HColumnDescriptor column) + throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + HTableDescriptor.isLegalTableName(tableName); + try { + this.master.addColumn(tableName, column); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + } + + /** + * Delete a column from a table + * + * @param tableName name of table + * @param columnName name of column to be deleted + * @throws IOException + */ + public void deleteColumn(final Text tableName, final Text columnName) + throws IOException { + deleteColumn(tableName.getBytes(), columnName.getBytes()); + } + + /** + * Delete a column from a table + * + * @param tableName name of table + * @param columnName name of column to be deleted + * @throws IOException + */ + public void deleteColumn(final String tableName, final String columnName) + throws IOException { + deleteColumn(Bytes.toBytes(tableName), Bytes.toBytes(columnName)); + } + + /** + * Delete a column from a table + * + * @param tableName name of table + * @param columnName name of column to be deleted + * @throws IOException + */ + public void deleteColumn(final byte [] tableName, final byte [] columnName) + throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + HTableDescriptor.isLegalTableName(tableName); + try { + this.master.deleteColumn(tableName, columnName); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + } + + /** + * Modify an existing column family on a table + * + * @param tableName name of table + * @param columnName name of column to be modified + * @param descriptor new column descriptor to use + * @throws IOException + */ + public void modifyColumn(final Text tableName, final Text columnName, + HColumnDescriptor descriptor) + throws IOException { + modifyColumn(tableName.getBytes(), columnName.getBytes(), descriptor); + } + + /** + * Modify an existing column family on a table + * + * @param tableName name of table + * @param columnName name of column to be modified + * @param descriptor new column descriptor to use + * @throws IOException + */ + public void modifyColumn(final String tableName, final String columnName, + HColumnDescriptor descriptor) + throws IOException { + modifyColumn(Bytes.toBytes(tableName), Bytes.toBytes(columnName), + descriptor); + } + + /** + * Modify an existing column family on a table + * + * @param tableName name of table + * @param columnName name of column to be modified + * @param descriptor new column descriptor to use + * @throws IOException + */ + public void modifyColumn(final byte [] tableName, final byte [] columnName, + HColumnDescriptor descriptor) + throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + HTableDescriptor.isLegalTableName(tableName); + try { + this.master.modifyColumn(tableName, columnName, descriptor); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + } + + /** + * Modify a table's HTableDescriptor + * + * @param tableName name of table + * @param desc the updated descriptor + * @throws IOException + */ + public void modifyTableMeta(final byte [] tableName, HTableDescriptor desc) + throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + HTableDescriptor.isLegalTableName(tableName); + try { + this.master.modifyTableMeta(tableName, desc); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + } + + /** + * Shuts down the HBase instance + * @throws IOException + */ + public synchronized void shutdown() throws IOException { + if (this.master == null) { + throw new MasterNotRunningException("master has been shut down"); + } + try { + this.master.shutdown(); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } finally { + this.master = null; + } + } + + private HRegionLocation getFirstMetaServerForTable(final byte [] tableName) + throws IOException { + return connection.locateRegion(HConstants.META_TABLE_NAME, + HRegionInfo.createRegionName(tableName, null, HConstants.NINES)); + } + + /** + * Check to see if HBase is running. Throw an exception if not. + * + * @param conf + * @throws MasterNotRunningException + */ + public static void checkHBaseAvailable(HBaseConfiguration conf) + throws MasterNotRunningException { + HBaseConfiguration copyOfConf = new HBaseConfiguration(conf); + copyOfConf.setInt("hbase.client.retries.number", 1); + new HBaseAdmin(copyOfConf); + } } \ No newline at end of file diff --git a/src/java/org/apache/hadoop/hbase/client/HConnectionManager.java b/src/java/org/apache/hadoop/hbase/client/HConnectionManager.java index 913dfa45b68..b5d5aa6d0fe 100644 --- a/src/java/org/apache/hadoop/hbase/client/HConnectionManager.java +++ b/src/java/org/apache/hadoop/hbase/client/HConnectionManager.java @@ -1,889 +1,889 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * 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.hadoop.hbase.client; - -import java.io.IOException; -import java.lang.reflect.UndeclaredThrowableException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.DoNotRetryIOException; -import org.apache.hadoop.hbase.HBaseConfiguration; -import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.HRegionInfo; -import org.apache.hadoop.hbase.HRegionLocation; -import org.apache.hadoop.hbase.HServerAddress; -import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.LocalHBaseCluster; -import org.apache.hadoop.hbase.MasterNotRunningException; -import org.apache.hadoop.hbase.RemoteExceptionHandler; -import org.apache.hadoop.hbase.TableNotFoundException; -import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; -import org.apache.hadoop.hbase.io.Cell; -import org.apache.hadoop.hbase.io.RowResult; -import org.apache.hadoop.hbase.ipc.HMasterInterface; -import org.apache.hadoop.hbase.ipc.HRegionInterface; -import org.apache.hadoop.hbase.ipc.HbaseRPC; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.SoftSortedMap; -import org.apache.hadoop.hbase.util.Writables; -import org.apache.hadoop.ipc.RemoteException; - -/** - * A non-instantiable class that manages connections to multiple tables in - * multiple HBase instances. - * - * Used by {@link HTable} and {@link HBaseAdmin} - */ -public class HConnectionManager implements HConstants { - /* - * Private. Not instantiable. - */ - private HConnectionManager() { - super(); - } - - // A Map of master HServerAddress -> connection information for that instance - // Note that although the Map is synchronized, the objects it contains - // are mutable and hence require synchronized access to them - private static final Map HBASE_INSTANCES = - new ConcurrentHashMap(); - - /** - * Get the connection object for the instance specified by the configuration - * If no current connection exists, create a new connection for that instance - * @param conf - * @return HConnection object for the instance specified by the configuration - */ - public static HConnection getConnection(HBaseConfiguration conf) { - TableServers connection; - synchronized (HBASE_INSTANCES) { - String instanceName = conf.get(HBASE_DIR); - connection = HBASE_INSTANCES.get(instanceName); - if (connection == null) { - connection = new TableServers(conf); - HBASE_INSTANCES.put(instanceName, connection); - } - } - return connection; - } - - /** - * Delete connection information for the instance specified by the configuration - * @param conf - */ - public static void deleteConnectionInfo(HBaseConfiguration conf) { - synchronized (HBASE_INSTANCES) { - HBASE_INSTANCES.remove(conf.get(HBASE_DIR)); - } - } - - /** - * Clear the static map of connection info. - */ - public static void deleteConnectionInfo() { - synchronized (HBASE_INSTANCES) { - HBASE_INSTANCES.clear(); - } - } - - - /* Encapsulates finding the servers for an HBase instance */ - private static class TableServers implements HConnection, HConstants { - private static final Log LOG = LogFactory.getLog(TableServers.class); - private final Class serverInterfaceClass; - private final long pause; - private final int numRetries; - private final int maxRPCAttempts; - - private final Integer masterLock = new Integer(0); - private volatile boolean closed; - private volatile HMasterInterface master; - private volatile boolean masterChecked; - - private final Integer rootRegionLock = new Integer(0); - private final Integer metaRegionLock = new Integer(0); - private final Integer userRegionLock = new Integer(0); - - private volatile HBaseConfiguration conf; - - // Known region HServerAddress.toString() -> HRegionInterface - private final Map servers = - new ConcurrentHashMap(); - - private HRegionLocation rootRegionLocation; - - private final Map> - cachedRegionLocations = Collections.synchronizedMap( - new HashMap>()); - - /** - * constructor - * @param conf Configuration object - */ - @SuppressWarnings("unchecked") - public TableServers(HBaseConfiguration conf) { - this.conf = LocalHBaseCluster.doLocal(new HBaseConfiguration(conf)); - - String serverClassName = - conf.get(REGION_SERVER_CLASS, DEFAULT_REGION_SERVER_CLASS); - - this.closed = false; - - try { - this.serverInterfaceClass = - (Class) Class.forName(serverClassName); - - } catch (ClassNotFoundException e) { - throw new UnsupportedOperationException( - "Unable to find region server interface " + serverClassName, e); - } - - this.pause = conf.getLong("hbase.client.pause", 10 * 1000); - this.numRetries = conf.getInt("hbase.client.retries.number", 10); - this.maxRPCAttempts = conf.getInt("hbase.client.rpc.maxattempts", 1); - - this.master = null; - this.masterChecked = false; - } - - private long getPauseTime(int tries) { - if (tries >= HConstants.RETRY_BACKOFF.length) - tries = HConstants.RETRY_BACKOFF.length - 1; - return this.pause * HConstants.RETRY_BACKOFF[tries]; - } - - /** {@inheritDoc} */ - public HMasterInterface getMaster() throws MasterNotRunningException { - HServerAddress masterLocation = null; - synchronized (this.masterLock) { - for (int tries = 0; - !this.closed && - !this.masterChecked && this.master == null && - tries < numRetries; - tries++) { - - masterLocation = new HServerAddress(this.conf.get(MASTER_ADDRESS, - DEFAULT_MASTER_ADDRESS)); - try { - HMasterInterface tryMaster = (HMasterInterface)HbaseRPC.getProxy( - HMasterInterface.class, HMasterInterface.versionID, - masterLocation.getInetSocketAddress(), this.conf); - - if (tryMaster.isMasterRunning()) { - this.master = tryMaster; - break; - } - - } catch (IOException e) { - if(tries == numRetries - 1) { - // This was our last chance - don't bother sleeping - break; - } - LOG.info("Attempt " + tries + " of " + this.numRetries + - " failed with <" + e + ">. Retrying after sleep of " + - getPauseTime(tries)); - } - - // We either cannot connect to master or it is not running. Sleep & retry - - try { - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e) { - // continue - } - } - this.masterChecked = true; - } - if (this.master == null) { - if (masterLocation == null) { - throw new MasterNotRunningException(); - } - throw new MasterNotRunningException(masterLocation.toString()); - } - return this.master; - } - - /** {@inheritDoc} */ - public boolean isMasterRunning() { - if (this.master == null) { - try { - getMaster(); - - } catch (MasterNotRunningException e) { - return false; - } - } - return true; - } - - /** {@inheritDoc} */ - public boolean tableExists(final byte [] tableName) - throws MasterNotRunningException { - getMaster(); - if (tableName == null) { - throw new IllegalArgumentException("Table name cannot be null"); - } - if (isMetaTableName(tableName)) { - return true; - } - boolean exists = false; - try { - HTableDescriptor[] tables = listTables(); - for (int i = 0; i < tables.length; i++) { - if (Bytes.equals(tables[i].getName(), tableName)) { - exists = true; - } - } - } catch (IOException e) { - LOG.warn("Testing for table existence threw exception", e); - } - return exists; - } - - /* - * @param n - * @return Truen if passed tablename n is equal to the name - * of a catalog table. - */ - private static boolean isMetaTableName(final byte [] n) { - return Bytes.equals(n, ROOT_TABLE_NAME) || - Bytes.equals(n, META_TABLE_NAME); - } - - /** {@inheritDoc} */ - public HRegionLocation getRegionLocation(final byte [] name, - final byte [] row, boolean reload) - throws IOException { - getMaster(); - return reload? relocateRegion(name, row): locateRegion(name, row); - } - - /** {@inheritDoc} */ - public HTableDescriptor[] listTables() throws IOException { - getMaster(); - final HashSet uniqueTables = - new HashSet(); - - MetaScannerVisitor visitor = new MetaScannerVisitor() { - - /** {@inheritDoc} */ - public boolean processRow(RowResult rowResult) throws IOException { - HRegionInfo info = Writables.getHRegionInfo( - rowResult.get(COL_REGIONINFO)); - - // Only examine the rows where the startKey is zero length - if (info.getStartKey().length == 0) { - uniqueTables.add(info.getTableDesc()); - } - return true; - } - - }; - MetaScanner.metaScan(conf, visitor); - - return uniqueTables.toArray(new HTableDescriptor[uniqueTables.size()]); - } - - /** {@inheritDoc} */ - public boolean isTableEnabled(byte[] tableName) throws IOException { - if (!tableExists(tableName)) { - throw new TableNotFoundException(Bytes.toString(tableName)); - } - if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { - // The root region is always enabled - return true; - } - - boolean result = true; - int rowsScanned = 0; - byte[] startKey = - HRegionInfo.createRegionName(tableName, null, HConstants.ZEROES); - HRegionInfo currentRegion = null; - do { - if (currentRegion != null) { - byte[] endKey = currentRegion.getEndKey(); - if (endKey == null || - Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)) { - // We have reached the end of the table and we're done - break; - } - } - HRegionInfo oldRegion = currentRegion; - if (oldRegion != null) { - startKey = oldRegion.getEndKey(); - } - ScannerCallable s = new ScannerCallable(this, - (Bytes.equals(tableName, HConstants.META_TABLE_NAME) ? - HConstants.ROOT_TABLE_NAME : HConstants.META_TABLE_NAME), - HConstants.COL_REGIONINFO_ARRAY, startKey, - HConstants.LATEST_TIMESTAMP, null - ); - // Open scanner - getRegionServerWithRetries(s); - currentRegion = s.getHRegionInfo(); - try { - RowResult r = null; - while (result && (r = getRegionServerWithRetries(s)) != null) { - Cell c = r.get(HConstants.COL_REGIONINFO); - if (c != null) { - byte[] value = c.getValue(); - if (value != null) { - HRegionInfo info = Writables.getHRegionInfoOrNull(value); - if (info != null) { - if (Bytes.equals(info.getTableDesc().getName(), tableName)) { - rowsScanned += 1; - result = !info.isOffline(); - } - } - } - } - } - } finally { - s.setClose(); - getRegionServerWithRetries(s); - } - } while (result); - return rowsScanned > 0 && result; - } - - private class HTableDescriptorFinder - implements MetaScanner.MetaScannerVisitor { - byte[] tableName; - HTableDescriptor result; - public HTableDescriptorFinder(byte[] tableName) { - this.tableName = tableName; - } - public boolean processRow(RowResult rowResult) throws IOException { - HRegionInfo info = Writables.getHRegionInfo( - rowResult.get(HConstants.COL_REGIONINFO)); - HTableDescriptor desc = info.getTableDesc(); - if (Bytes.compareTo(desc.getName(), tableName) == 0) { - result = desc; - return false; - } - return true; - } - HTableDescriptor getResult() { - return result; - } - } - - /** {@inheritDoc} */ - public HTableDescriptor getHTableDescriptor(final byte[] tableName) - throws IOException { - if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { - return new UnmodifyableHTableDescriptor(HTableDescriptor.ROOT_TABLEDESC); - } - if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) { - return new UnmodifyableHTableDescriptor(HTableDescriptor.META_TABLEDESC); - } - HTableDescriptorFinder finder = new HTableDescriptorFinder(tableName); - MetaScanner.metaScan(conf, finder); - HTableDescriptor result = finder.getResult(); - if (result == null) { - throw new TableNotFoundException(Bytes.toString(tableName)); - } - return result; - } - - /** {@inheritDoc} */ - public HRegionLocation locateRegion(final byte [] tableName, - final byte [] row) - throws IOException{ - getMaster(); - return locateRegion(tableName, row, true); - } - - /** {@inheritDoc} */ - public HRegionLocation relocateRegion(final byte [] tableName, - final byte [] row) - throws IOException{ - getMaster(); - return locateRegion(tableName, row, false); - } - - private HRegionLocation locateRegion(final byte [] tableName, - final byte [] row, boolean useCache) - throws IOException{ - if (tableName == null || tableName.length == 0) { - throw new IllegalArgumentException( - "table name cannot be null or zero length"); - } - - if (Bytes.equals(tableName, ROOT_TABLE_NAME)) { - synchronized (rootRegionLock) { - // This block guards against two threads trying to find the root - // region at the same time. One will go do the find while the - // second waits. The second thread will not do find. - - if (!useCache || rootRegionLocation == null) { - return locateRootRegion(); - } - return rootRegionLocation; - } - } else if (Bytes.equals(tableName, META_TABLE_NAME)) { - synchronized (metaRegionLock) { - // This block guards against two threads trying to load the meta - // region at the same time. The first will load the meta region and - // the second will use the value that the first one found. - - return locateRegionInMeta(ROOT_TABLE_NAME, tableName, row, useCache); - } - } else { - synchronized(userRegionLock){ - return locateRegionInMeta(META_TABLE_NAME, tableName, row, useCache); - } - } - } - - /** - * Search one of the meta tables (-ROOT- or .META.) for the HRegionLocation - * info that contains the table and row we're seeking. - */ - private HRegionLocation locateRegionInMeta(final byte [] parentTable, - final byte [] tableName, final byte [] row, boolean useCache) - throws IOException{ - HRegionLocation location = null; - - // if we're supposed to be using the cache, then check it for a possible - // hit. otherwise, delete any existing cached location so it won't - // interfere. - if (useCache) { - location = getCachedLocation(tableName, row); - if (location != null) { - return location; - } - } else { - deleteCachedLocation(tableName, row); - } - - // build the key of the meta region we should be looking for. - // the extra 9's on the end are necessary to allow "exact" matches - // without knowing the precise region names. - byte [] metaKey = HRegionInfo.createRegionName(tableName, row, - HConstants.NINES); - for (int tries = 0; true; tries++) { - if (tries >= numRetries) { - throw new NoServerForRegionException("Unable to find region for " - + Bytes.toString(row) + " after " + numRetries + " tries."); - } - - try{ - // locate the root region - HRegionLocation metaLocation = locateRegion(parentTable, metaKey); - HRegionInterface server = - getHRegionConnection(metaLocation.getServerAddress()); - - // query the root region for the location of the meta region - RowResult regionInfoRow = server.getClosestRowBefore( - metaLocation.getRegionInfo().getRegionName(), metaKey); - - if (regionInfoRow == null) { - throw new TableNotFoundException(Bytes.toString(tableName)); - } - - Cell value = regionInfoRow.get(COL_REGIONINFO); - - if (value == null || value.getValue().length == 0) { - throw new IOException("HRegionInfo was null or empty in " + - Bytes.toString(parentTable)); - } - - // convert the row result into the HRegionLocation we need! - HRegionInfo regionInfo = (HRegionInfo) Writables.getWritable( - value.getValue(), new HRegionInfo()); - - // possible we got a region of a different table... - if (!Bytes.equals(regionInfo.getTableDesc().getName(), tableName)) { - throw new TableNotFoundException( - "Table '" + Bytes.toString(tableName) + "' was not found."); - } - - if (regionInfo.isOffline()) { - throw new RegionOfflineException("region offline: " + - regionInfo.getRegionNameAsString()); - } - - String serverAddress = - Writables.cellToString(regionInfoRow.get(COL_SERVER)); - - if (serverAddress.equals("")) { - throw new NoServerForRegionException("No server address listed " + - "in " + Bytes.toString(parentTable) + " for region " + - regionInfo.getRegionNameAsString()); - } - - // instantiate the location - location = new HRegionLocation(regionInfo, - new HServerAddress(serverAddress)); - - cacheLocation(tableName, location); - - return location; - } catch (TableNotFoundException e) { - // if we got this error, probably means the table just plain doesn't - // exist. rethrow the error immediately. this should always be coming - // from the HTable constructor. - throw e; - } catch (IOException e) { - if (e instanceof RemoteException) { - e = RemoteExceptionHandler.decodeRemoteException( - (RemoteException) e); - } - if (tries < numRetries - 1) { - if (LOG.isDebugEnabled()) { - LOG.debug("reloading table servers because: " + e.getMessage()); - } - relocateRegion(parentTable, metaKey); - } else { - throw e; - } - } - - try{ - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e){ - // continue - } - } - } - - /* - * Search the cache for a location that fits our table and row key. - * Return null if no suitable region is located. TODO: synchronization note - * - *

TODO: This method during writing consumes 15% of CPU doing lookup - * into the Soft Reference SortedMap. Improve. - * - * @param tableName - * @param row - * @return Null or region location found in cache. - */ - private HRegionLocation getCachedLocation(final byte [] tableName, - final byte [] row) { - // find the map of cached locations for this table - Integer key = Bytes.mapKey(tableName); - SoftSortedMap tableLocations = - cachedRegionLocations.get(key); - - // if tableLocations for this table isn't built yet, make one - if (tableLocations == null) { - tableLocations = new SoftSortedMap(Bytes.BYTES_COMPARATOR); - cachedRegionLocations.put(key, tableLocations); - } - - // start to examine the cache. we can only do cache actions - // if there's something in the cache for this table. - if (tableLocations.isEmpty()) { - return null; - } - - HRegionLocation rl = tableLocations.get(row); - if (rl != null) { - if (LOG.isDebugEnabled()) { - LOG.debug("Cache hit in table locations for row <" + - Bytes.toString(row) + - "> and tableName " + Bytes.toString(tableName) + - ": location server " + rl.getServerAddress() + - ", location region name " + - rl.getRegionInfo().getRegionNameAsString()); - } - return rl; - } - - // Cut the cache so that we only get the part that could contain - // regions that match our key - SoftSortedMap matchingRegions = - tableLocations.headMap(row); - - // if that portion of the map is empty, then we're done. otherwise, - // we need to examine the cached location to verify that it is - // a match by end key as well. - if (!matchingRegions.isEmpty()) { - HRegionLocation possibleRegion = - matchingRegions.get(matchingRegions.lastKey()); - - // there is a possibility that the reference was garbage collected - // in the instant since we checked isEmpty(). - if (possibleRegion != null) { - byte[] endKey = possibleRegion.getRegionInfo().getEndKey(); - - // make sure that the end key is greater than the row we're looking - // for, otherwise the row actually belongs in the next region, not - // this one. the exception case is when the endkey is EMPTY_START_ROW, - // signifying that the region we're checking is actually the last - // region in the table. - if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) || - Bytes.compareTo(endKey, row) > 0) { - return possibleRegion; - } - } - } - - // Passed all the way through, so we got nothin - complete cache miss - return null; - } - - /** - * Delete a cached location, if it satisfies the table name and row - * requirements. - */ - private void deleteCachedLocation(final byte [] tableName, - final byte [] row) { - // find the map of cached locations for this table - Integer key = Bytes.mapKey(tableName); - SoftSortedMap tableLocations = - cachedRegionLocations.get(key); - - // if tableLocations for this table isn't built yet, make one - if (tableLocations == null) { - tableLocations = - new SoftSortedMap(Bytes.BYTES_COMPARATOR); - cachedRegionLocations.put(key, tableLocations); - } - - // start to examine the cache. we can only do cache actions - // if there's something in the cache for this table. - if (!tableLocations.isEmpty()) { - // cut the cache so that we only get the part that could contain - // regions that match our key - SoftSortedMap matchingRegions = - tableLocations.headMap(row); - - // if that portion of the map is empty, then we're done. otherwise, - // we need to examine the cached location to verify that it is - // a match by end key as well. - if (!matchingRegions.isEmpty()) { - HRegionLocation possibleRegion = - matchingRegions.get(matchingRegions.lastKey()); - - byte [] endKey = possibleRegion.getRegionInfo().getEndKey(); - - // by nature of the map, we know that the start key has to be < - // otherwise it wouldn't be in the headMap. - if (Bytes.compareTo(endKey, row) <= 0) { - // delete any matching entry - HRegionLocation rl = - tableLocations.remove(matchingRegions.lastKey()); - if (rl != null && LOG.isDebugEnabled()) { - LOG.debug("Removed " + rl.getRegionInfo().getRegionNameAsString() + - " from cache because of " + Bytes.toString(row)); - } - } - } - } - } - - /** - * Put a newly discovered HRegionLocation into the cache. - */ - private void cacheLocation(final byte [] tableName, - final HRegionLocation location){ - byte [] startKey = location.getRegionInfo().getStartKey(); - - // find the map of cached locations for this table - Integer key = Bytes.mapKey(tableName); - SoftSortedMap tableLocations = - cachedRegionLocations.get(key); - - // if tableLocations for this table isn't built yet, make one - if (tableLocations == null) { - tableLocations = - new SoftSortedMap(Bytes.BYTES_COMPARATOR); - cachedRegionLocations.put(key, tableLocations); - } - - // save the HRegionLocation under the startKey - tableLocations.put(startKey, location); - } - - /** {@inheritDoc} */ - public HRegionInterface getHRegionConnection(HServerAddress regionServer) - throws IOException { - getMaster(); - HRegionInterface server; - synchronized (this.servers) { - // See if we already have a connection - server = this.servers.get(regionServer.toString()); - if (server == null) { // Get a connection - long versionId = 0; - try { - versionId = - serverInterfaceClass.getDeclaredField("versionID").getLong(server); - } catch (IllegalAccessException e) { - // Should never happen unless visibility of versionID changes - throw new UnsupportedOperationException( - "Unable to open a connection to a " + - serverInterfaceClass.getName() + " server.", e); - } catch (NoSuchFieldException e) { - // Should never happen unless versionID field name changes in HRegionInterface - throw new UnsupportedOperationException( - "Unable to open a connection to a " + - serverInterfaceClass.getName() + " server.", e); - } - - try { - server = (HRegionInterface)HbaseRPC.waitForProxy(serverInterfaceClass, - versionId, regionServer.getInetSocketAddress(), this.conf, - this.maxRPCAttempts); - } catch (RemoteException e) { - throw RemoteExceptionHandler.decodeRemoteException(e); - } - this.servers.put(regionServer.toString(), server); - } - } - return server; - } - - /* - * Repeatedly try to find the root region by asking the master for where it is - * @return HRegionLocation for root region if found - * @throws NoServerForRegionException - if the root region can not be located - * after retrying - * @throws IOException - */ - private HRegionLocation locateRootRegion() - throws IOException { - getMaster(); - HServerAddress rootRegionAddress = null; - for (int tries = 0; tries < numRetries; tries++) { - int localTimeouts = 0; - - // ask the master which server has the root region - while (rootRegionAddress == null && localTimeouts < numRetries) { - rootRegionAddress = master.findRootRegion(); - if (rootRegionAddress == null) { - try { - if (LOG.isDebugEnabled()) { - LOG.debug("Sleeping. Waiting for root region."); - } - Thread.sleep(getPauseTime(tries)); - if (LOG.isDebugEnabled()) { - LOG.debug("Wake. Retry finding root region."); - } - } catch (InterruptedException iex) { - // continue - } - localTimeouts++; - } - } - - if (rootRegionAddress == null) { - throw new NoServerForRegionException( - "Timed out trying to locate root region"); - } - - // get a connection to the region server - HRegionInterface server = getHRegionConnection(rootRegionAddress); - - try { - // if this works, then we're good, and we have an acceptable address, - // so we can stop doing retries and return the result. - server.getRegionInfo(HRegionInfo.ROOT_REGIONINFO.getRegionName()); - if (LOG.isDebugEnabled()) { - LOG.debug("Found ROOT " + HRegionInfo.ROOT_REGIONINFO); - } - break; - } catch (IOException e) { - if (tries == numRetries - 1) { - // Don't bother sleeping. We've run out of retries. - if (e instanceof RemoteException) { - e = RemoteExceptionHandler.decodeRemoteException( - (RemoteException) e); - } - throw e; - } - - // Sleep and retry finding root region. - try { - if (LOG.isDebugEnabled()) { - LOG.debug("Root region location changed. Sleeping."); - } - Thread.sleep(getPauseTime(tries)); - if (LOG.isDebugEnabled()) { - LOG.debug("Wake. Retry finding root region."); - } - } catch (InterruptedException iex) { - // continue - } - } - - rootRegionAddress = null; - } - - // if the address is null by this point, then the retries have failed, - // and we're sort of sunk - if (rootRegionAddress == null) { - throw new NoServerForRegionException( - "unable to locate root region server"); - } - - // return the region location - return new HRegionLocation( - HRegionInfo.ROOT_REGIONINFO, rootRegionAddress); - } - - /** {@inheritDoc} */ - public T getRegionServerWithRetries(ServerCallable callable) - throws IOException, RuntimeException { - getMaster(); - List exceptions = new ArrayList(); - for(int tries = 0; tries < numRetries; tries++) { - try { - callable.instantiateServer(tries != 0); - return callable.call(); - } catch (Throwable t) { - if (t instanceof UndeclaredThrowableException) { - t = t.getCause(); - } - if (t instanceof RemoteException) { - t = RemoteExceptionHandler.decodeRemoteException((RemoteException) t); - } - if (t instanceof DoNotRetryIOException) { - throw (DoNotRetryIOException)t; - } - exceptions.add(t); - if (tries == numRetries - 1) { - throw new RetriesExhaustedException(callable.getServerName(), - callable.getRegionName(), callable.getRow(), tries, exceptions); - } - if (LOG.isDebugEnabled()) { - LOG.debug("reloading table servers because: " + t.getMessage()); - } - } - try { - Thread.sleep(getPauseTime(tries)); - } catch (InterruptedException e) { - // continue - } - } - return null; - } - } -} +/** + * Copyright 2007 The Apache Software Foundation + * + * 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.hadoop.hbase.client; + +import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.DoNotRetryIOException; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HRegionLocation; +import org.apache.hadoop.hbase.HServerAddress; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.LocalHBaseCluster; +import org.apache.hadoop.hbase.MasterNotRunningException; +import org.apache.hadoop.hbase.RemoteExceptionHandler; +import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; +import org.apache.hadoop.hbase.io.Cell; +import org.apache.hadoop.hbase.io.RowResult; +import org.apache.hadoop.hbase.ipc.HMasterInterface; +import org.apache.hadoop.hbase.ipc.HRegionInterface; +import org.apache.hadoop.hbase.ipc.HbaseRPC; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.SoftSortedMap; +import org.apache.hadoop.hbase.util.Writables; +import org.apache.hadoop.ipc.RemoteException; + +/** + * A non-instantiable class that manages connections to multiple tables in + * multiple HBase instances. + * + * Used by {@link HTable} and {@link HBaseAdmin} + */ +public class HConnectionManager implements HConstants { + /* + * Private. Not instantiable. + */ + private HConnectionManager() { + super(); + } + + // A Map of master HServerAddress -> connection information for that instance + // Note that although the Map is synchronized, the objects it contains + // are mutable and hence require synchronized access to them + private static final Map HBASE_INSTANCES = + new ConcurrentHashMap(); + + /** + * Get the connection object for the instance specified by the configuration + * If no current connection exists, create a new connection for that instance + * @param conf + * @return HConnection object for the instance specified by the configuration + */ + public static HConnection getConnection(HBaseConfiguration conf) { + TableServers connection; + synchronized (HBASE_INSTANCES) { + String instanceName = conf.get(HBASE_DIR); + connection = HBASE_INSTANCES.get(instanceName); + if (connection == null) { + connection = new TableServers(conf); + HBASE_INSTANCES.put(instanceName, connection); + } + } + return connection; + } + + /** + * Delete connection information for the instance specified by the configuration + * @param conf + */ + public static void deleteConnectionInfo(HBaseConfiguration conf) { + synchronized (HBASE_INSTANCES) { + HBASE_INSTANCES.remove(conf.get(HBASE_DIR)); + } + } + + /** + * Clear the static map of connection info. + */ + public static void deleteConnectionInfo() { + synchronized (HBASE_INSTANCES) { + HBASE_INSTANCES.clear(); + } + } + + + /* Encapsulates finding the servers for an HBase instance */ + private static class TableServers implements HConnection, HConstants { + private static final Log LOG = LogFactory.getLog(TableServers.class); + private final Class serverInterfaceClass; + private final long pause; + private final int numRetries; + private final int maxRPCAttempts; + + private final Integer masterLock = new Integer(0); + private volatile boolean closed; + private volatile HMasterInterface master; + private volatile boolean masterChecked; + + private final Integer rootRegionLock = new Integer(0); + private final Integer metaRegionLock = new Integer(0); + private final Integer userRegionLock = new Integer(0); + + private volatile HBaseConfiguration conf; + + // Known region HServerAddress.toString() -> HRegionInterface + private final Map servers = + new ConcurrentHashMap(); + + private HRegionLocation rootRegionLocation; + + private final Map> + cachedRegionLocations = Collections.synchronizedMap( + new HashMap>()); + + /** + * constructor + * @param conf Configuration object + */ + @SuppressWarnings("unchecked") + public TableServers(HBaseConfiguration conf) { + this.conf = LocalHBaseCluster.doLocal(new HBaseConfiguration(conf)); + + String serverClassName = + conf.get(REGION_SERVER_CLASS, DEFAULT_REGION_SERVER_CLASS); + + this.closed = false; + + try { + this.serverInterfaceClass = + (Class) Class.forName(serverClassName); + + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException( + "Unable to find region server interface " + serverClassName, e); + } + + this.pause = conf.getLong("hbase.client.pause", 10 * 1000); + this.numRetries = conf.getInt("hbase.client.retries.number", 10); + this.maxRPCAttempts = conf.getInt("hbase.client.rpc.maxattempts", 1); + + this.master = null; + this.masterChecked = false; + } + + private long getPauseTime(int tries) { + if (tries >= HConstants.RETRY_BACKOFF.length) + tries = HConstants.RETRY_BACKOFF.length - 1; + return this.pause * HConstants.RETRY_BACKOFF[tries]; + } + + /** {@inheritDoc} */ + public HMasterInterface getMaster() throws MasterNotRunningException { + HServerAddress masterLocation = null; + synchronized (this.masterLock) { + for (int tries = 0; + !this.closed && + !this.masterChecked && this.master == null && + tries < numRetries; + tries++) { + + masterLocation = new HServerAddress(this.conf.get(MASTER_ADDRESS, + DEFAULT_MASTER_ADDRESS)); + try { + HMasterInterface tryMaster = (HMasterInterface)HbaseRPC.getProxy( + HMasterInterface.class, HMasterInterface.versionID, + masterLocation.getInetSocketAddress(), this.conf); + + if (tryMaster.isMasterRunning()) { + this.master = tryMaster; + break; + } + + } catch (IOException e) { + if(tries == numRetries - 1) { + // This was our last chance - don't bother sleeping + break; + } + LOG.info("Attempt " + tries + " of " + this.numRetries + + " failed with <" + e + ">. Retrying after sleep of " + + getPauseTime(tries)); + } + + // We either cannot connect to master or it is not running. Sleep & retry + + try { + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e) { + // continue + } + } + this.masterChecked = true; + } + if (this.master == null) { + if (masterLocation == null) { + throw new MasterNotRunningException(); + } + throw new MasterNotRunningException(masterLocation.toString()); + } + return this.master; + } + + /** {@inheritDoc} */ + public boolean isMasterRunning() { + if (this.master == null) { + try { + getMaster(); + + } catch (MasterNotRunningException e) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean tableExists(final byte [] tableName) + throws MasterNotRunningException { + getMaster(); + if (tableName == null) { + throw new IllegalArgumentException("Table name cannot be null"); + } + if (isMetaTableName(tableName)) { + return true; + } + boolean exists = false; + try { + HTableDescriptor[] tables = listTables(); + for (int i = 0; i < tables.length; i++) { + if (Bytes.equals(tables[i].getName(), tableName)) { + exists = true; + } + } + } catch (IOException e) { + LOG.warn("Testing for table existence threw exception", e); + } + return exists; + } + + /* + * @param n + * @return Truen if passed tablename n is equal to the name + * of a catalog table. + */ + private static boolean isMetaTableName(final byte [] n) { + return Bytes.equals(n, ROOT_TABLE_NAME) || + Bytes.equals(n, META_TABLE_NAME); + } + + /** {@inheritDoc} */ + public HRegionLocation getRegionLocation(final byte [] name, + final byte [] row, boolean reload) + throws IOException { + getMaster(); + return reload? relocateRegion(name, row): locateRegion(name, row); + } + + /** {@inheritDoc} */ + public HTableDescriptor[] listTables() throws IOException { + getMaster(); + final HashSet uniqueTables = + new HashSet(); + + MetaScannerVisitor visitor = new MetaScannerVisitor() { + + /** {@inheritDoc} */ + public boolean processRow(RowResult rowResult) throws IOException { + HRegionInfo info = Writables.getHRegionInfo( + rowResult.get(COL_REGIONINFO)); + + // Only examine the rows where the startKey is zero length + if (info.getStartKey().length == 0) { + uniqueTables.add(info.getTableDesc()); + } + return true; + } + + }; + MetaScanner.metaScan(conf, visitor); + + return uniqueTables.toArray(new HTableDescriptor[uniqueTables.size()]); + } + + /** {@inheritDoc} */ + public boolean isTableEnabled(byte[] tableName) throws IOException { + if (!tableExists(tableName)) { + throw new TableNotFoundException(Bytes.toString(tableName)); + } + if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { + // The root region is always enabled + return true; + } + + boolean result = true; + int rowsScanned = 0; + byte[] startKey = + HRegionInfo.createRegionName(tableName, null, HConstants.ZEROES); + HRegionInfo currentRegion = null; + do { + if (currentRegion != null) { + byte[] endKey = currentRegion.getEndKey(); + if (endKey == null || + Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY)) { + // We have reached the end of the table and we're done + break; + } + } + HRegionInfo oldRegion = currentRegion; + if (oldRegion != null) { + startKey = oldRegion.getEndKey(); + } + ScannerCallable s = new ScannerCallable(this, + (Bytes.equals(tableName, HConstants.META_TABLE_NAME) ? + HConstants.ROOT_TABLE_NAME : HConstants.META_TABLE_NAME), + HConstants.COL_REGIONINFO_ARRAY, startKey, + HConstants.LATEST_TIMESTAMP, null + ); + // Open scanner + getRegionServerWithRetries(s); + currentRegion = s.getHRegionInfo(); + try { + RowResult r = null; + while (result && (r = getRegionServerWithRetries(s)) != null) { + Cell c = r.get(HConstants.COL_REGIONINFO); + if (c != null) { + byte[] value = c.getValue(); + if (value != null) { + HRegionInfo info = Writables.getHRegionInfoOrNull(value); + if (info != null) { + if (Bytes.equals(info.getTableDesc().getName(), tableName)) { + rowsScanned += 1; + result = !info.isOffline(); + } + } + } + } + } + } finally { + s.setClose(); + getRegionServerWithRetries(s); + } + } while (result); + return rowsScanned > 0 && result; + } + + private class HTableDescriptorFinder + implements MetaScanner.MetaScannerVisitor { + byte[] tableName; + HTableDescriptor result; + public HTableDescriptorFinder(byte[] tableName) { + this.tableName = tableName; + } + public boolean processRow(RowResult rowResult) throws IOException { + HRegionInfo info = Writables.getHRegionInfo( + rowResult.get(HConstants.COL_REGIONINFO)); + HTableDescriptor desc = info.getTableDesc(); + if (Bytes.compareTo(desc.getName(), tableName) == 0) { + result = desc; + return false; + } + return true; + } + HTableDescriptor getResult() { + return result; + } + } + + /** {@inheritDoc} */ + public HTableDescriptor getHTableDescriptor(final byte[] tableName) + throws IOException { + if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { + return new UnmodifyableHTableDescriptor(HTableDescriptor.ROOT_TABLEDESC); + } + if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) { + return new UnmodifyableHTableDescriptor(HTableDescriptor.META_TABLEDESC); + } + HTableDescriptorFinder finder = new HTableDescriptorFinder(tableName); + MetaScanner.metaScan(conf, finder); + HTableDescriptor result = finder.getResult(); + if (result == null) { + throw new TableNotFoundException(Bytes.toString(tableName)); + } + return result; + } + + /** {@inheritDoc} */ + public HRegionLocation locateRegion(final byte [] tableName, + final byte [] row) + throws IOException{ + getMaster(); + return locateRegion(tableName, row, true); + } + + /** {@inheritDoc} */ + public HRegionLocation relocateRegion(final byte [] tableName, + final byte [] row) + throws IOException{ + getMaster(); + return locateRegion(tableName, row, false); + } + + private HRegionLocation locateRegion(final byte [] tableName, + final byte [] row, boolean useCache) + throws IOException{ + if (tableName == null || tableName.length == 0) { + throw new IllegalArgumentException( + "table name cannot be null or zero length"); + } + + if (Bytes.equals(tableName, ROOT_TABLE_NAME)) { + synchronized (rootRegionLock) { + // This block guards against two threads trying to find the root + // region at the same time. One will go do the find while the + // second waits. The second thread will not do find. + + if (!useCache || rootRegionLocation == null) { + return locateRootRegion(); + } + return rootRegionLocation; + } + } else if (Bytes.equals(tableName, META_TABLE_NAME)) { + synchronized (metaRegionLock) { + // This block guards against two threads trying to load the meta + // region at the same time. The first will load the meta region and + // the second will use the value that the first one found. + + return locateRegionInMeta(ROOT_TABLE_NAME, tableName, row, useCache); + } + } else { + synchronized(userRegionLock){ + return locateRegionInMeta(META_TABLE_NAME, tableName, row, useCache); + } + } + } + + /** + * Search one of the meta tables (-ROOT- or .META.) for the HRegionLocation + * info that contains the table and row we're seeking. + */ + private HRegionLocation locateRegionInMeta(final byte [] parentTable, + final byte [] tableName, final byte [] row, boolean useCache) + throws IOException{ + HRegionLocation location = null; + + // if we're supposed to be using the cache, then check it for a possible + // hit. otherwise, delete any existing cached location so it won't + // interfere. + if (useCache) { + location = getCachedLocation(tableName, row); + if (location != null) { + return location; + } + } else { + deleteCachedLocation(tableName, row); + } + + // build the key of the meta region we should be looking for. + // the extra 9's on the end are necessary to allow "exact" matches + // without knowing the precise region names. + byte [] metaKey = HRegionInfo.createRegionName(tableName, row, + HConstants.NINES); + for (int tries = 0; true; tries++) { + if (tries >= numRetries) { + throw new NoServerForRegionException("Unable to find region for " + + Bytes.toString(row) + " after " + numRetries + " tries."); + } + + try{ + // locate the root region + HRegionLocation metaLocation = locateRegion(parentTable, metaKey); + HRegionInterface server = + getHRegionConnection(metaLocation.getServerAddress()); + + // query the root region for the location of the meta region + RowResult regionInfoRow = server.getClosestRowBefore( + metaLocation.getRegionInfo().getRegionName(), metaKey); + + if (regionInfoRow == null) { + throw new TableNotFoundException(Bytes.toString(tableName)); + } + + Cell value = regionInfoRow.get(COL_REGIONINFO); + + if (value == null || value.getValue().length == 0) { + throw new IOException("HRegionInfo was null or empty in " + + Bytes.toString(parentTable)); + } + + // convert the row result into the HRegionLocation we need! + HRegionInfo regionInfo = (HRegionInfo) Writables.getWritable( + value.getValue(), new HRegionInfo()); + + // possible we got a region of a different table... + if (!Bytes.equals(regionInfo.getTableDesc().getName(), tableName)) { + throw new TableNotFoundException( + "Table '" + Bytes.toString(tableName) + "' was not found."); + } + + if (regionInfo.isOffline()) { + throw new RegionOfflineException("region offline: " + + regionInfo.getRegionNameAsString()); + } + + String serverAddress = + Writables.cellToString(regionInfoRow.get(COL_SERVER)); + + if (serverAddress.equals("")) { + throw new NoServerForRegionException("No server address listed " + + "in " + Bytes.toString(parentTable) + " for region " + + regionInfo.getRegionNameAsString()); + } + + // instantiate the location + location = new HRegionLocation(regionInfo, + new HServerAddress(serverAddress)); + + cacheLocation(tableName, location); + + return location; + } catch (TableNotFoundException e) { + // if we got this error, probably means the table just plain doesn't + // exist. rethrow the error immediately. this should always be coming + // from the HTable constructor. + throw e; + } catch (IOException e) { + if (e instanceof RemoteException) { + e = RemoteExceptionHandler.decodeRemoteException( + (RemoteException) e); + } + if (tries < numRetries - 1) { + if (LOG.isDebugEnabled()) { + LOG.debug("reloading table servers because: " + e.getMessage()); + } + relocateRegion(parentTable, metaKey); + } else { + throw e; + } + } + + try{ + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e){ + // continue + } + } + } + + /* + * Search the cache for a location that fits our table and row key. + * Return null if no suitable region is located. TODO: synchronization note + * + *

TODO: This method during writing consumes 15% of CPU doing lookup + * into the Soft Reference SortedMap. Improve. + * + * @param tableName + * @param row + * @return Null or region location found in cache. + */ + private HRegionLocation getCachedLocation(final byte [] tableName, + final byte [] row) { + // find the map of cached locations for this table + Integer key = Bytes.mapKey(tableName); + SoftSortedMap tableLocations = + cachedRegionLocations.get(key); + + // if tableLocations for this table isn't built yet, make one + if (tableLocations == null) { + tableLocations = new SoftSortedMap(Bytes.BYTES_COMPARATOR); + cachedRegionLocations.put(key, tableLocations); + } + + // start to examine the cache. we can only do cache actions + // if there's something in the cache for this table. + if (tableLocations.isEmpty()) { + return null; + } + + HRegionLocation rl = tableLocations.get(row); + if (rl != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Cache hit in table locations for row <" + + Bytes.toString(row) + + "> and tableName " + Bytes.toString(tableName) + + ": location server " + rl.getServerAddress() + + ", location region name " + + rl.getRegionInfo().getRegionNameAsString()); + } + return rl; + } + + // Cut the cache so that we only get the part that could contain + // regions that match our key + SoftSortedMap matchingRegions = + tableLocations.headMap(row); + + // if that portion of the map is empty, then we're done. otherwise, + // we need to examine the cached location to verify that it is + // a match by end key as well. + if (!matchingRegions.isEmpty()) { + HRegionLocation possibleRegion = + matchingRegions.get(matchingRegions.lastKey()); + + // there is a possibility that the reference was garbage collected + // in the instant since we checked isEmpty(). + if (possibleRegion != null) { + byte[] endKey = possibleRegion.getRegionInfo().getEndKey(); + + // make sure that the end key is greater than the row we're looking + // for, otherwise the row actually belongs in the next region, not + // this one. the exception case is when the endkey is EMPTY_START_ROW, + // signifying that the region we're checking is actually the last + // region in the table. + if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) || + Bytes.compareTo(endKey, row) > 0) { + return possibleRegion; + } + } + } + + // Passed all the way through, so we got nothin - complete cache miss + return null; + } + + /** + * Delete a cached location, if it satisfies the table name and row + * requirements. + */ + private void deleteCachedLocation(final byte [] tableName, + final byte [] row) { + // find the map of cached locations for this table + Integer key = Bytes.mapKey(tableName); + SoftSortedMap tableLocations = + cachedRegionLocations.get(key); + + // if tableLocations for this table isn't built yet, make one + if (tableLocations == null) { + tableLocations = + new SoftSortedMap(Bytes.BYTES_COMPARATOR); + cachedRegionLocations.put(key, tableLocations); + } + + // start to examine the cache. we can only do cache actions + // if there's something in the cache for this table. + if (!tableLocations.isEmpty()) { + // cut the cache so that we only get the part that could contain + // regions that match our key + SoftSortedMap matchingRegions = + tableLocations.headMap(row); + + // if that portion of the map is empty, then we're done. otherwise, + // we need to examine the cached location to verify that it is + // a match by end key as well. + if (!matchingRegions.isEmpty()) { + HRegionLocation possibleRegion = + matchingRegions.get(matchingRegions.lastKey()); + + byte [] endKey = possibleRegion.getRegionInfo().getEndKey(); + + // by nature of the map, we know that the start key has to be < + // otherwise it wouldn't be in the headMap. + if (Bytes.compareTo(endKey, row) <= 0) { + // delete any matching entry + HRegionLocation rl = + tableLocations.remove(matchingRegions.lastKey()); + if (rl != null && LOG.isDebugEnabled()) { + LOG.debug("Removed " + rl.getRegionInfo().getRegionNameAsString() + + " from cache because of " + Bytes.toString(row)); + } + } + } + } + } + + /** + * Put a newly discovered HRegionLocation into the cache. + */ + private void cacheLocation(final byte [] tableName, + final HRegionLocation location){ + byte [] startKey = location.getRegionInfo().getStartKey(); + + // find the map of cached locations for this table + Integer key = Bytes.mapKey(tableName); + SoftSortedMap tableLocations = + cachedRegionLocations.get(key); + + // if tableLocations for this table isn't built yet, make one + if (tableLocations == null) { + tableLocations = + new SoftSortedMap(Bytes.BYTES_COMPARATOR); + cachedRegionLocations.put(key, tableLocations); + } + + // save the HRegionLocation under the startKey + tableLocations.put(startKey, location); + } + + /** {@inheritDoc} */ + public HRegionInterface getHRegionConnection(HServerAddress regionServer) + throws IOException { + getMaster(); + HRegionInterface server; + synchronized (this.servers) { + // See if we already have a connection + server = this.servers.get(regionServer.toString()); + if (server == null) { // Get a connection + long versionId = 0; + try { + versionId = + serverInterfaceClass.getDeclaredField("versionID").getLong(server); + } catch (IllegalAccessException e) { + // Should never happen unless visibility of versionID changes + throw new UnsupportedOperationException( + "Unable to open a connection to a " + + serverInterfaceClass.getName() + " server.", e); + } catch (NoSuchFieldException e) { + // Should never happen unless versionID field name changes in HRegionInterface + throw new UnsupportedOperationException( + "Unable to open a connection to a " + + serverInterfaceClass.getName() + " server.", e); + } + + try { + server = (HRegionInterface)HbaseRPC.waitForProxy(serverInterfaceClass, + versionId, regionServer.getInetSocketAddress(), this.conf, + this.maxRPCAttempts); + } catch (RemoteException e) { + throw RemoteExceptionHandler.decodeRemoteException(e); + } + this.servers.put(regionServer.toString(), server); + } + } + return server; + } + + /* + * Repeatedly try to find the root region by asking the master for where it is + * @return HRegionLocation for root region if found + * @throws NoServerForRegionException - if the root region can not be located + * after retrying + * @throws IOException + */ + private HRegionLocation locateRootRegion() + throws IOException { + getMaster(); + HServerAddress rootRegionAddress = null; + for (int tries = 0; tries < numRetries; tries++) { + int localTimeouts = 0; + + // ask the master which server has the root region + while (rootRegionAddress == null && localTimeouts < numRetries) { + rootRegionAddress = master.findRootRegion(); + if (rootRegionAddress == null) { + try { + if (LOG.isDebugEnabled()) { + LOG.debug("Sleeping. Waiting for root region."); + } + Thread.sleep(getPauseTime(tries)); + if (LOG.isDebugEnabled()) { + LOG.debug("Wake. Retry finding root region."); + } + } catch (InterruptedException iex) { + // continue + } + localTimeouts++; + } + } + + if (rootRegionAddress == null) { + throw new NoServerForRegionException( + "Timed out trying to locate root region"); + } + + // get a connection to the region server + HRegionInterface server = getHRegionConnection(rootRegionAddress); + + try { + // if this works, then we're good, and we have an acceptable address, + // so we can stop doing retries and return the result. + server.getRegionInfo(HRegionInfo.ROOT_REGIONINFO.getRegionName()); + if (LOG.isDebugEnabled()) { + LOG.debug("Found ROOT " + HRegionInfo.ROOT_REGIONINFO); + } + break; + } catch (IOException e) { + if (tries == numRetries - 1) { + // Don't bother sleeping. We've run out of retries. + if (e instanceof RemoteException) { + e = RemoteExceptionHandler.decodeRemoteException( + (RemoteException) e); + } + throw e; + } + + // Sleep and retry finding root region. + try { + if (LOG.isDebugEnabled()) { + LOG.debug("Root region location changed. Sleeping."); + } + Thread.sleep(getPauseTime(tries)); + if (LOG.isDebugEnabled()) { + LOG.debug("Wake. Retry finding root region."); + } + } catch (InterruptedException iex) { + // continue + } + } + + rootRegionAddress = null; + } + + // if the address is null by this point, then the retries have failed, + // and we're sort of sunk + if (rootRegionAddress == null) { + throw new NoServerForRegionException( + "unable to locate root region server"); + } + + // return the region location + return new HRegionLocation( + HRegionInfo.ROOT_REGIONINFO, rootRegionAddress); + } + + /** {@inheritDoc} */ + public T getRegionServerWithRetries(ServerCallable callable) + throws IOException, RuntimeException { + getMaster(); + List exceptions = new ArrayList(); + for(int tries = 0; tries < numRetries; tries++) { + try { + callable.instantiateServer(tries != 0); + return callable.call(); + } catch (Throwable t) { + if (t instanceof UndeclaredThrowableException) { + t = t.getCause(); + } + if (t instanceof RemoteException) { + t = RemoteExceptionHandler.decodeRemoteException((RemoteException) t); + } + if (t instanceof DoNotRetryIOException) { + throw (DoNotRetryIOException)t; + } + exceptions.add(t); + if (tries == numRetries - 1) { + throw new RetriesExhaustedException(callable.getServerName(), + callable.getRegionName(), callable.getRow(), tries, exceptions); + } + if (LOG.isDebugEnabled()) { + LOG.debug("reloading table servers because: " + t.getMessage()); + } + } + try { + Thread.sleep(getPauseTime(tries)); + } catch (InterruptedException e) { + // continue + } + } + return null; + } + } +} diff --git a/src/java/org/apache/hadoop/hbase/client/HTable.java b/src/java/org/apache/hadoop/hbase/client/HTable.java index 5e96834a3b6..6d086e91fc4 100644 --- a/src/java/org/apache/hadoop/hbase/client/HTable.java +++ b/src/java/org/apache/hadoop/hbase/client/HTable.java @@ -1,1408 +1,1408 @@ -/** - * Copyright 2008 The Apache Software Foundation - * - * 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.hadoop.hbase.client; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.HBaseConfiguration; -import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.HRegionInfo; -import org.apache.hadoop.hbase.HRegionLocation; -import org.apache.hadoop.hbase.HServerAddress; -import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; -import org.apache.hadoop.hbase.filter.RowFilterInterface; -import org.apache.hadoop.hbase.filter.StopRowFilter; -import org.apache.hadoop.hbase.filter.WhileMatchRowFilter; -import org.apache.hadoop.hbase.io.BatchUpdate; -import org.apache.hadoop.hbase.io.Cell; -import org.apache.hadoop.hbase.io.RowResult; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Writables; -import org.apache.hadoop.io.Text; - -/** - * Used to communicate with a single HBase table - */ -public class HTable { - private final HConnection connection; - private final byte [] tableName; - private HBaseConfiguration configuration; - - /** - * Creates an object to access a HBase table - * - * @param tableName name of the table - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public HTable(final Text tableName) - throws IOException { - this(new HBaseConfiguration(), tableName.getBytes()); - } - - /** - * Creates an object to access a HBase table - * - * @param tableName name of the table - * @throws IOException - */ - public HTable(final String tableName) - throws IOException { - this(new HBaseConfiguration(), Bytes.toBytes(tableName)); - } - - /** - * Creates an object to access a HBase table - * - * @param tableName name of the table - * @throws IOException - */ - public HTable(final byte [] tableName) - throws IOException { - this(new HBaseConfiguration(), tableName); - } - - /** - * Creates an object to access a HBase table - * - * @param conf configuration object - * @param tableName name of the table - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public HTable(HBaseConfiguration conf, final Text tableName) - throws IOException { - this(conf, tableName.getBytes()); - } - - /** - * Creates an object to access a HBase table - * - * @param conf configuration object - * @param tableName name of the table - * @throws IOException - */ - public HTable(HBaseConfiguration conf, final String tableName) - throws IOException { - this(conf, Bytes.toBytes(tableName)); - } - - /** - * Creates an object to access a HBase table - * - * @param conf configuration object - * @param tableName name of the table - * @throws IOException - */ - public HTable(HBaseConfiguration conf, final byte [] tableName) - throws IOException { - this.connection = HConnectionManager.getConnection(conf); - this.configuration = conf; - this.tableName = tableName; - this.connection.locateRegion(tableName, HConstants.EMPTY_START_ROW); - } - - /** - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public static boolean isTableEnabled(Text tableName) throws IOException { - return isTableEnabled(tableName.getBytes()); - } - /** - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public static boolean isTableEnabled(String tableName) throws IOException { - return isTableEnabled(Bytes.toBytes(tableName)); - } - /** - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public static boolean isTableEnabled(byte[] tableName) throws IOException { - return isTableEnabled(new HBaseConfiguration(), tableName); - } - - /** - * @param conf HBaseConfiguration object - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public static boolean isTableEnabled(HBaseConfiguration conf, Text tableName) - throws IOException { - return isTableEnabled(conf, tableName.getBytes()); - } - - /** - * @param conf HBaseConfiguration object - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public static boolean isTableEnabled(HBaseConfiguration conf, String tableName) - throws IOException { - return isTableEnabled(conf, Bytes.toBytes(tableName)); - } - - /** - * @param conf HBaseConfiguration object - * @param tableName name of table to check - * @return true if table is on-line - * @throws IOException - */ - public static boolean isTableEnabled(HBaseConfiguration conf, byte[] tableName) - throws IOException { - return HConnectionManager.getConnection(conf).isTableEnabled(tableName); - } - - /** - * Find region location hosting passed row using cached info - * @param row Row to find. - * @return Location of row. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public HRegionLocation getRegionLocation(final Text row) - throws IOException { - return connection.getRegionLocation(tableName, row.getBytes(), false); - } - - /** - * Find region location hosting passed row using cached info - * @param row Row to find. - * @return Location of row. - * @throws IOException - */ - public HRegionLocation getRegionLocation(final String row) - throws IOException { - return connection.getRegionLocation(tableName, Bytes.toBytes(row), false); - } - - /** - * Find region location hosting passed row using cached info - * @param row Row to find. - * @return Location of row. - * @throws IOException - */ - public HRegionLocation getRegionLocation(final byte [] row) - throws IOException { - return connection.getRegionLocation(tableName, row, false); - } - - /** @return the table name */ - public byte [] getTableName() { - return this.tableName; - } - - /** - * Used by unit tests and tools to do low-level manipulations. Not for - * general use. - * @return An HConnection instance. - */ - public HConnection getConnection() { - return this.connection; - } - - /** - * @return table metadata - * @throws IOException - */ - @Deprecated - public HTableDescriptor getMetadata() throws IOException { - return getTableDescriptor(); - } - - /** - * @return table metadata - * @throws IOException - */ - public HTableDescriptor getTableDescriptor() throws IOException { - return new UnmodifyableHTableDescriptor( - this.connection.getHTableDescriptor(this.tableName)); - } - - /** - * Gets the starting row key for every region in the currently open table - * - * @return Array of region starting row keys - * @throws IOException - */ - @SuppressWarnings("null") - public byte[][] getStartKeys() throws IOException { - final List keyList = new ArrayList(); - - MetaScannerVisitor visitor = new MetaScannerVisitor() { - public boolean processRow(RowResult rowResult) throws IOException { - HRegionInfo info = Writables.getHRegionInfo( - rowResult.get(HConstants.COL_REGIONINFO)); - if (Bytes.equals(info.getTableDesc().getName(), getTableName())) { - if (!(info.isOffline() || info.isSplit())) { - keyList.add(info.getStartKey()); - } - } - return true; - } - - }; - MetaScanner.metaScan(configuration, visitor, this.tableName); - return keyList.toArray(new byte[keyList.size()][]); - } - - /** - * Get all the regions and their address for this table - * - * @return A map of HRegionInfo with it's server address - * @throws IOException - */ - public Map getRegionsInfo() throws IOException { - final Map regionMap = - new TreeMap(); - - MetaScannerVisitor visitor = new MetaScannerVisitor() { - public boolean processRow(RowResult rowResult) throws IOException { - HRegionInfo info = Writables.getHRegionInfo( - rowResult.get(HConstants.COL_REGIONINFO)); - - if (!(Bytes.equals(info.getTableDesc().getName(), getTableName()))) { - return false; - } - - HServerAddress server = new HServerAddress(); - Cell c = rowResult.get(HConstants.COL_SERVER); - if (c != null && c.getValue() != null && c.getValue().length > 0) { - String address = Bytes.toString(c.getValue()); - server = new HServerAddress(address); - } - - if (!(info.isOffline() || info.isSplit())) { - regionMap.put(new UnmodifyableHRegionInfo(info), server); - } - return true; - } - - }; - MetaScanner.metaScan(configuration, visitor, tableName); - return regionMap; - } - - /** - * Get a single value for the specified row and column - * - * @param row row key - * @param column column name - * @return value for specified row/column - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Cell get(final Text row, final Text column) - throws IOException { - return get(row.getBytes(), column.getBytes()); - } - - /** - * Get a single value for the specified row and column - * - * @param row row key - * @param column column name - * @param numVersions - number of versions to retrieve - * @return value for specified row/column - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Cell[] get(final Text row, final Text column, int numVersions) - throws IOException { - return get(row.getBytes(), column.getBytes(), numVersions); - } - - /** - * Get a single value for the specified row and column - * - * @param row row key - * @param column column name - * @return value for specified row/column - * @throws IOException - */ - public Cell get(final String row, final String column) - throws IOException { - return get(Bytes.toBytes(row), Bytes.toBytes(column)); - } - - /** - * Get a single value for the specified row and column - * - * @param row row key - * @param column column name - * @param numVersions - number of versions to retrieve - * @return value for specified row/column - * @throws IOException - */ - public Cell[] get(final String row, final String column, int numVersions) - throws IOException { - return get(Bytes.toBytes(row), Bytes.toBytes(column), numVersions); - } - - /** - * Get a single value for the specified row and column - * - * @param row row key - * @param column column name - * @return value for specified row/column - * @throws IOException - */ - public Cell get(final byte [] row, final byte [] column) - throws IOException { - return connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Cell call() throws IOException { - return server.get(location.getRegionInfo().getRegionName(), row, - column); - } - } - ); - } - - /** - * Get the specified number of versions of the specified row and column - * @param row row key - * @param column column name - * @param numVersions number of versions to retrieve - * @return Array of Cells. - * @throws IOException - */ - public Cell[] get(final byte [] row, final byte [] column, - final int numVersions) - throws IOException { - return connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Cell[] call() throws IOException { - return server.get(location.getRegionInfo().getRegionName(), row, - column, numVersions); - } - } - ); - } - - /** - * Get the specified number of versions of the specified row and column with - * the specified timestamp. - * - * @param row - row key - * @param column - column name - * @param timestamp - timestamp - * @param numVersions - number of versions to retrieve - * @return - array of values that match the above criteria - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Cell[] get(final Text row, final Text column, - final long timestamp, final int numVersions) - throws IOException { - return get(row.getBytes(), column.getBytes(), timestamp, numVersions); - } - - /** - * Get the specified number of versions of the specified row and column with - * the specified timestamp. - * - * @param row - row key - * @param column - column name - * @param timestamp - timestamp - * @param numVersions - number of versions to retrieve - * @return - array of values that match the above criteria - * @throws IOException - */ - public Cell[] get(final String row, final String column, - final long timestamp, final int numVersions) - throws IOException { - return get(Bytes.toBytes(row), Bytes.toBytes(column), timestamp, numVersions); - } - - /** - * Get the specified number of versions of the specified row and column with - * the specified timestamp. - * - * @param row - row key - * @param column - column name - * @param timestamp - timestamp - * @param numVersions - number of versions to retrieve - * @return - array of values that match the above criteria - * @throws IOException - */ - public Cell[] get(final byte [] row, final byte [] column, - final long timestamp, final int numVersions) - throws IOException { - Cell[] values = null; - values = connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Cell[] call() throws IOException { - return server.get(location.getRegionInfo().getRegionName(), row, - column, timestamp, numVersions); - } - } - ); - - if (values != null) { - ArrayList cellValues = new ArrayList(); - for (int i = 0 ; i < values.length; i++) { - cellValues.add(values[i]); - } - return cellValues.toArray(new Cell[values.length]); - } - return null; - } - - /** - * Get all the data for the specified row at the latest timestamp - * - * @param row row key - * @return RowResult is empty if row does not exist. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public RowResult getRow(final Text row) throws IOException { - return getRow(row.getBytes()); - } - - /** - * Get all the data for the specified row at the latest timestamp - * - * @param row row key - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final String row) throws IOException { - return getRow(Bytes.toBytes(row)); - } - - /** - * Get all the data for the specified row at the latest timestamp - * - * @param row row key - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final byte [] row) throws IOException { - return getRow(row, HConstants.LATEST_TIMESTAMP); - } - - /** - * Get all the data for the specified row at a specified timestamp - * - * @param row row key - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public RowResult getRow(final Text row, final long ts) - throws IOException { - return getRow(row.getBytes(), ts); - } - - /** - * Get all the data for the specified row at a specified timestamp - * - * @param row row key - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final String row, final long ts) - throws IOException { - return getRow(Bytes.toBytes(row), ts); - } - - /** - * Get all the data for the specified row at a specified timestamp - * - * @param row row key - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final byte [] row, final long ts) - throws IOException { - return getRow(row,null,ts); - } - - /** - * Get selected columns for the specified row at the latest timestamp - * - * @param row row key - * @param columns Array of column names and families you want to retrieve. - * @return RowResult is empty if row does not exist. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public RowResult getRow(final Text row, final Text[] columns) - throws IOException { - return getRow(row.getBytes(), Bytes.toByteArrays(columns)); - } - - /** - * Get selected columns for the specified row at the latest timestamp - * - * @param row row key - * @param columns Array of column names and families you want to retrieve. - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final String row, final String [] columns) - throws IOException { - return getRow(Bytes.toBytes(row), Bytes.toByteArrays(columns)); - } - - /** - * Get selected columns for the specified row at the latest timestamp - * - * @param row row key - * @param columns Array of column names and families you want to retrieve. - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final byte [] row, final byte [][] columns) - throws IOException { - return getRow(row, columns, HConstants.LATEST_TIMESTAMP); - } - - /** - * Get selected columns for the specified row at a specified timestamp - * - * @param row row key - * @param columns Array of column names and families you want to retrieve. - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public RowResult getRow(final Text row, final Text [] columns, - final long ts) - throws IOException { - return getRow(row.getBytes(), Bytes.toByteArrays(columns), ts); - } - - /** - * Get selected columns for the specified row at a specified timestamp - * - * @param row row key - * @param columns Array of column names and families you want to retrieve. - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final String row, final String [] columns, - final long ts) - throws IOException { - return getRow(Bytes.toBytes(row), Bytes.toByteArrays(columns), ts); - } - - /** - * Get selected columns for the specified row at a specified timestamp - * - * @param row row key - * @param columns Array of column names and families you want to retrieve. - * @param ts timestamp - * @return RowResult is empty if row does not exist. - * @throws IOException - */ - public RowResult getRow(final byte [] row, final byte [][] columns, - final long ts) - throws IOException { - return connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public RowResult call() throws IOException { - return server.getRow(location.getRegionInfo().getRegionName(), row, - columns, ts); - } - } - ); - } - - /** - * Get a scanner on the current table starting at first row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @return scanner - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Scanner getScanner(final Text [] columns) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), HConstants.EMPTY_START_ROW); - } - - /** - * Get a scanner on the current table starting at first row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final String [] columns) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), HConstants.EMPTY_START_ROW); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @return scanner - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Scanner getScanner(final Text [] columns, final Text startRow) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), startRow.getBytes()); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final String [] columns, final String startRow) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow)); - } - - /** - * Get a scanner on the current table starting at first row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte[][] columns) - throws IOException { - return getScanner(columns, HConstants.EMPTY_START_ROW, - HConstants.LATEST_TIMESTAMP, null); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte[][] columns, final byte [] startRow) - throws IOException { - return getScanner(columns, startRow, HConstants.LATEST_TIMESTAMP, null); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param timestamp only return results whose timestamp <= this value - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte[][] columns, final byte [] startRow, - long timestamp) - throws IOException { - return getScanner(columns, startRow, timestamp, null); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param filter a row filter using row-key regexp and/or column data filter. - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte[][] columns, final byte [] startRow, - RowFilterInterface filter) - throws IOException { - return getScanner(columns, startRow, HConstants.LATEST_TIMESTAMP, filter); - } - - /** - * Get a scanner on the current table starting at the specified row and - * ending just before stopRow. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param stopRow Row to stop scanning on. Once we hit this row we stop - * returning values; i.e. we return the row before this one but not the - * stopRow itself. - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte [][] columns, - final byte [] startRow, final byte [] stopRow) - throws IOException { - return getScanner(columns, startRow, stopRow, - HConstants.LATEST_TIMESTAMP); - } - - /** - * Get a scanner on the current table starting at the specified row and - * ending just before stopRow. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param stopRow Row to stop scanning on. Once we hit this row we stop - * returning values; i.e. we return the row before this one but not the - * stopRow itself. - * @param timestamp only return results whose timestamp <= this value - * @return scanner - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Scanner getScanner(final Text[] columns, - final Text startRow, final Text stopRow, final long timestamp) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), startRow.getBytes(), - stopRow.getBytes(), timestamp); - } - - /** - * Get a scanner on the current table starting at the specified row and - * ending just before stopRow. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param stopRow Row to stop scanning on. Once we hit this row we stop - * returning values; i.e. we return the row before this one but not the - * stopRow itself. - * @param timestamp only return results whose timestamp <= this value - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final String [] columns, - final String startRow, final String stopRow, final long timestamp) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow), - Bytes.toBytes(stopRow), timestamp); - } - - /** - * Get a scanner on the current table starting at the specified row and - * ending just before stopRow. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param stopRow Row to stop scanning on. Once we hit this row we stop - * returning values; i.e. we return the row before this one but not the - * stopRow itself. - * @param timestamp only return results whose timestamp <= this value - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte [][] columns, - final byte [] startRow, final byte [] stopRow, final long timestamp) - throws IOException { - return getScanner(columns, startRow, timestamp, - new WhileMatchRowFilter(new StopRowFilter(stopRow))); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param timestamp only return results whose timestamp <= this value - * @param filter a row filter using row-key regexp and/or column data filter. - * @return scanner - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public Scanner getScanner(Text[] columns, - Text startRow, long timestamp, RowFilterInterface filter) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), startRow.getBytes(), - timestamp, filter); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param timestamp only return results whose timestamp <= this value - * @param filter a row filter using row-key regexp and/or column data filter. - * @return scanner - * @throws IOException - */ - public Scanner getScanner(String[] columns, - String startRow, long timestamp, RowFilterInterface filter) - throws IOException { - return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow), - timestamp, filter); - } - - /** - * Get a scanner on the current table starting at the specified row. - * Return the specified columns. - * - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex in the column qualifier. A column qualifier is judged to - * be a regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row in table to scan - * @param timestamp only return results whose timestamp <= this value - * @param filter a row filter using row-key regexp and/or column data filter. - * @return scanner - * @throws IOException - */ - public Scanner getScanner(final byte [][] columns, - final byte [] startRow, long timestamp, RowFilterInterface filter) - throws IOException { - return new ClientScanner(columns, startRow, timestamp, filter); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @throws IOException - */ - public void deleteAll(final byte [] row) throws IOException { - deleteAll(row, null); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public void deleteAll(final Text row) throws IOException { - deleteAll(row, null); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @throws IOException - */ - public void deleteAll(final String row) throws IOException { - deleteAll(row, null); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @param column column to be deleted - * @throws IOException - */ - public void deleteAll(final byte [] row, final byte [] column) - throws IOException { - deleteAll(row, column, HConstants.LATEST_TIMESTAMP); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @param ts Delete all cells of the same timestamp or older. - * @throws IOException - */ - public void deleteAll(final byte [] row, final long ts) - throws IOException { - deleteAll(row, null, ts); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @param ts Delete all cells of the same timestamp or older. - * @throws IOException - */ - public void deleteAll(final String row, final long ts) - throws IOException { - deleteAll(row, null, ts); - } - - /** - * Completely delete the row's cells. - * - * @param row Key of the row you want to completely delete. - * @param ts Delete all cells of the same timestamp or older. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public void deleteAll(final Text row, final long ts) - throws IOException { - deleteAll(row, null, ts); - } - - /** - * Delete all cells that match the passed row and column. - * @param row Row to update - * @param column name of column whose value is to be deleted - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public void deleteAll(final Text row, final Text column) throws IOException { - deleteAll(row, column, HConstants.LATEST_TIMESTAMP); - } - - /** - * Delete all cells that match the passed row and column. - * @param row Row to update - * @param column name of column whose value is to be deleted - * @throws IOException - */ - public void deleteAll(final String row, final String column) - throws IOException { - deleteAll(row, column, HConstants.LATEST_TIMESTAMP); - } - - /** - * Delete all cells that match the passed row and column and whose - * timestamp is equal-to or older than the passed timestamp. - * @param row Row to update - * @param column name of column whose value is to be deleted - * @param ts Delete all cells of the same timestamp or older. - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public void deleteAll(final Text row, final Text column, final long ts) - throws IOException { - deleteAll(row.getBytes(), column.getBytes(), ts); - } - - /** - * Delete all cells that match the passed row and column and whose - * timestamp is equal-to or older than the passed timestamp. - * @param row Row to update - * @param column name of column whose value is to be deleted - * @param ts Delete all cells of the same timestamp or older. - * @throws IOException - */ - public void deleteAll(final String row, final String column, final long ts) - throws IOException { - deleteAll(Bytes.toBytes(row), - column != null? Bytes.toBytes(column): null, ts); - } - - /** - * Delete all cells that match the passed row and column and whose - * timestamp is equal-to or older than the passed timestamp. - * @param row Row to update - * @param column name of column whose value is to be deleted - * @param ts Delete all cells of the same timestamp or older. - * @throws IOException - */ - public void deleteAll(final byte [] row, final byte [] column, final long ts) - throws IOException { - connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Boolean call() throws IOException { - if (column != null) { - this.server.deleteAll(location.getRegionInfo().getRegionName(), - row, column, ts); - } else { - this.server.deleteAll(location.getRegionInfo().getRegionName(), - row, ts); - } - return null; - } - } - ); - } - - /** - * Delete all cells for a row with matching column family at all timestamps. - * - * @param row The row to operate on - * @param family The column family to match - * @param timestamp Timestamp to match - * @throws IOException - * @deprecated Use String or byte [] overload instead - */ - public void deleteFamily(final Text row, final Text family, - final long timestamp) - throws IOException{ - deleteFamily(row.getBytes(), family.getBytes(), timestamp); - } - - /** - * Delete all cells for a row with matching column family at all timestamps. - * - * @param row The row to operate on - * @param family The column family to match - * @param timestamp Timestamp to match - * @throws IOException - */ - public void deleteFamily(final String row, final String family, - final long timestamp) - throws IOException{ - deleteFamily(Bytes.toBytes(row), Bytes.toBytes(family), timestamp); - } - - /** - * Delete all cells for a row with matching column family with timestamps - * less than or equal to timestamp. - * - * @param row The row to operate on - * @param family The column family to match - * @param timestamp Timestamp to match - * @throws IOException - */ - public void deleteFamily(final byte [] row, final byte [] family, - final long timestamp) - throws IOException { - connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, row) { - public Boolean call() throws IOException { - server.deleteFamily(location.getRegionInfo().getRegionName(), row, - family, timestamp); - return null; - } - } - ); - } - - /** - * Commit a BatchUpdate to the table. - * @param batchUpdate - * @throws IOException - */ - public synchronized void commit(final BatchUpdate batchUpdate) - throws IOException { - connection.getRegionServerWithRetries( - new ServerCallable(connection, tableName, batchUpdate.getRow()) { - public Boolean call() throws IOException { - server.batchUpdate(location.getRegionInfo().getRegionName(), - batchUpdate); - return null; - } - } - ); - } - - /** - * Commit a RowsBatchUpdate to the table. - * @param batchUpdates - * @throws IOException - */ - public synchronized void commit(final List batchUpdates) - throws IOException { - for (BatchUpdate batchUpdate : batchUpdates) - commit(batchUpdate); - } - - /** - * Implements the scanner interface for the HBase client. - * If there are multiple regions in a table, this scanner will iterate - * through them all. - */ - protected class ClientScanner implements Scanner { - private final Log CLIENT_LOG = LogFactory.getLog(this.getClass()); - private byte[][] columns; - private byte [] startRow; - protected long scanTime; - @SuppressWarnings("hiding") - private boolean closed = false; - private HRegionInfo currentRegion = null; - private ScannerCallable callable = null; - protected RowFilterInterface filter; - - protected ClientScanner(final Text [] columns, final Text startRow, - long timestamp, RowFilterInterface filter) - throws IOException { - this(Bytes.toByteArrays(columns), startRow.getBytes(), timestamp, - filter); - } - - protected ClientScanner(final byte[][] columns, final byte [] startRow, - final long timestamp, final RowFilterInterface filter) - throws IOException { - if (CLIENT_LOG.isDebugEnabled()) { - CLIENT_LOG.debug("Creating scanner over " + Bytes.toString(getTableName()) + - " starting at key '" + Bytes.toString(startRow) + "'"); - } - // save off the simple parameters - this.columns = columns; - this.startRow = startRow; - this.scanTime = timestamp; - - // save the filter, and make sure that the filter applies to the data - // we're expecting to pull back - this.filter = filter; - if (filter != null) { - filter.validate(columns); - } - nextScanner(); - } - - protected byte[][] getColumns() { - return columns; - } - - protected long getTimestamp() { - return scanTime; - } - - protected RowFilterInterface getFilter() { - return filter; - } - - /* - * Gets a scanner for the next region. - * Returns false if there are no more scanners. - */ - private boolean nextScanner() throws IOException { - // Close the previous scanner if it's open - if (this.callable != null) { - this.callable.setClose(); - getConnection().getRegionServerWithRetries(callable); - this.callable = null; - } - - // if we're at the end of the table, then close and return false - // to stop iterating - if (currentRegion != null) { - if (CLIENT_LOG.isDebugEnabled()) { - CLIENT_LOG.debug("Advancing forward from region " + currentRegion); - } - - byte [] endKey = currentRegion.getEndKey(); - if (endKey == null || - Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY) || - filterSaysStop(endKey)) { - close(); - return false; - } - } - - HRegionInfo oldRegion = this.currentRegion; - byte [] localStartKey = oldRegion == null? startRow: oldRegion.getEndKey(); - - if (CLIENT_LOG.isDebugEnabled()) { - CLIENT_LOG.debug("Advancing internal scanner to startKey at '" + - Bytes.toString(localStartKey) + "'"); - } - - try { - callable = getScannerCallable(localStartKey); - // open a scanner on the region server starting at the - // beginning of the region - getConnection().getRegionServerWithRetries(callable); - currentRegion = callable.getHRegionInfo(); - } catch (IOException e) { - close(); - throw e; - } - return true; - } - - protected ScannerCallable getScannerCallable(byte [] localStartKey) { - return new ScannerCallable(getConnection(), getTableName(), columns, - localStartKey, scanTime, filter); - } - - /** - * @param endKey - * @return Returns true if the passed region endkey is judged beyond - * filter. - */ - private boolean filterSaysStop(final byte [] endKey) { - if (this.filter == null) { - return false; - } - // Let the filter see current row. - this.filter.filterRowKey(endKey); - return this.filter.filterAllRemaining(); - } - - /** {@inheritDoc} */ - public RowResult next() throws IOException { - if (this.closed) { - return null; - } - RowResult values = null; - do { - values = getConnection().getRegionServerWithRetries(callable); - } while ((values == null || values.size() == 0) && nextScanner()); - - if (values != null && values.size() != 0) { - return values; - } - return null; - } - - /** - * {@inheritDoc} - */ - public void close() { - if (callable != null) { - callable.setClose(); - try { - getConnection().getRegionServerWithRetries(callable); - } catch (IOException e) { - // We used to catch this error, interpret, and rethrow. However, we - // have since decided that it's not nice for a scanner's close to - // throw exceptions. Chances are it was just an UnknownScanner - // exception due to lease time out. - } - callable = null; - } - closed = true; - } - - /** {@inheritDoc} */ - public Iterator iterator() { - return new Iterator() { - // The next RowResult, possibly pre-read - RowResult next = null; - - // return true if there is another item pending, false if there isn't. - // this method is where the actual advancing takes place, but you need - // to call next() to consume it. hasNext() will only advance if there - // isn't a pending next(). - public boolean hasNext() { - if (next == null) { - try { - next = ClientScanner.this.next(); - return next != null; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - return true; - } - - // get the pending next item and advance the iterator. returns null if - // there is no next item. - public RowResult next() { - // since hasNext() does the real advancing, we call this to determine - // if there is a next before proceeding. - if (!hasNext()) { - return null; - } - - // if we get to here, then hasNext() has given us an item to return. - // we want to return the item and then null out the next pointer, so - // we use a temporary variable. - RowResult temp = next; - next = null; - return temp; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - } -} +/** + * Copyright 2008 The Apache Software Foundation + * + * 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.hadoop.hbase.client; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HRegionLocation; +import org.apache.hadoop.hbase.HServerAddress; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; +import org.apache.hadoop.hbase.filter.RowFilterInterface; +import org.apache.hadoop.hbase.filter.StopRowFilter; +import org.apache.hadoop.hbase.filter.WhileMatchRowFilter; +import org.apache.hadoop.hbase.io.BatchUpdate; +import org.apache.hadoop.hbase.io.Cell; +import org.apache.hadoop.hbase.io.RowResult; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Writables; +import org.apache.hadoop.io.Text; + +/** + * Used to communicate with a single HBase table + */ +public class HTable { + private final HConnection connection; + private final byte [] tableName; + private HBaseConfiguration configuration; + + /** + * Creates an object to access a HBase table + * + * @param tableName name of the table + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public HTable(final Text tableName) + throws IOException { + this(new HBaseConfiguration(), tableName.getBytes()); + } + + /** + * Creates an object to access a HBase table + * + * @param tableName name of the table + * @throws IOException + */ + public HTable(final String tableName) + throws IOException { + this(new HBaseConfiguration(), Bytes.toBytes(tableName)); + } + + /** + * Creates an object to access a HBase table + * + * @param tableName name of the table + * @throws IOException + */ + public HTable(final byte [] tableName) + throws IOException { + this(new HBaseConfiguration(), tableName); + } + + /** + * Creates an object to access a HBase table + * + * @param conf configuration object + * @param tableName name of the table + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public HTable(HBaseConfiguration conf, final Text tableName) + throws IOException { + this(conf, tableName.getBytes()); + } + + /** + * Creates an object to access a HBase table + * + * @param conf configuration object + * @param tableName name of the table + * @throws IOException + */ + public HTable(HBaseConfiguration conf, final String tableName) + throws IOException { + this(conf, Bytes.toBytes(tableName)); + } + + /** + * Creates an object to access a HBase table + * + * @param conf configuration object + * @param tableName name of the table + * @throws IOException + */ + public HTable(HBaseConfiguration conf, final byte [] tableName) + throws IOException { + this.connection = HConnectionManager.getConnection(conf); + this.configuration = conf; + this.tableName = tableName; + this.connection.locateRegion(tableName, HConstants.EMPTY_START_ROW); + } + + /** + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public static boolean isTableEnabled(Text tableName) throws IOException { + return isTableEnabled(tableName.getBytes()); + } + /** + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public static boolean isTableEnabled(String tableName) throws IOException { + return isTableEnabled(Bytes.toBytes(tableName)); + } + /** + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public static boolean isTableEnabled(byte[] tableName) throws IOException { + return isTableEnabled(new HBaseConfiguration(), tableName); + } + + /** + * @param conf HBaseConfiguration object + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public static boolean isTableEnabled(HBaseConfiguration conf, Text tableName) + throws IOException { + return isTableEnabled(conf, tableName.getBytes()); + } + + /** + * @param conf HBaseConfiguration object + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public static boolean isTableEnabled(HBaseConfiguration conf, String tableName) + throws IOException { + return isTableEnabled(conf, Bytes.toBytes(tableName)); + } + + /** + * @param conf HBaseConfiguration object + * @param tableName name of table to check + * @return true if table is on-line + * @throws IOException + */ + public static boolean isTableEnabled(HBaseConfiguration conf, byte[] tableName) + throws IOException { + return HConnectionManager.getConnection(conf).isTableEnabled(tableName); + } + + /** + * Find region location hosting passed row using cached info + * @param row Row to find. + * @return Location of row. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public HRegionLocation getRegionLocation(final Text row) + throws IOException { + return connection.getRegionLocation(tableName, row.getBytes(), false); + } + + /** + * Find region location hosting passed row using cached info + * @param row Row to find. + * @return Location of row. + * @throws IOException + */ + public HRegionLocation getRegionLocation(final String row) + throws IOException { + return connection.getRegionLocation(tableName, Bytes.toBytes(row), false); + } + + /** + * Find region location hosting passed row using cached info + * @param row Row to find. + * @return Location of row. + * @throws IOException + */ + public HRegionLocation getRegionLocation(final byte [] row) + throws IOException { + return connection.getRegionLocation(tableName, row, false); + } + + /** @return the table name */ + public byte [] getTableName() { + return this.tableName; + } + + /** + * Used by unit tests and tools to do low-level manipulations. Not for + * general use. + * @return An HConnection instance. + */ + public HConnection getConnection() { + return this.connection; + } + + /** + * @return table metadata + * @throws IOException + */ + @Deprecated + public HTableDescriptor getMetadata() throws IOException { + return getTableDescriptor(); + } + + /** + * @return table metadata + * @throws IOException + */ + public HTableDescriptor getTableDescriptor() throws IOException { + return new UnmodifyableHTableDescriptor( + this.connection.getHTableDescriptor(this.tableName)); + } + + /** + * Gets the starting row key for every region in the currently open table + * + * @return Array of region starting row keys + * @throws IOException + */ + @SuppressWarnings("null") + public byte[][] getStartKeys() throws IOException { + final List keyList = new ArrayList(); + + MetaScannerVisitor visitor = new MetaScannerVisitor() { + public boolean processRow(RowResult rowResult) throws IOException { + HRegionInfo info = Writables.getHRegionInfo( + rowResult.get(HConstants.COL_REGIONINFO)); + if (Bytes.equals(info.getTableDesc().getName(), getTableName())) { + if (!(info.isOffline() || info.isSplit())) { + keyList.add(info.getStartKey()); + } + } + return true; + } + + }; + MetaScanner.metaScan(configuration, visitor, this.tableName); + return keyList.toArray(new byte[keyList.size()][]); + } + + /** + * Get all the regions and their address for this table + * + * @return A map of HRegionInfo with it's server address + * @throws IOException + */ + public Map getRegionsInfo() throws IOException { + final Map regionMap = + new TreeMap(); + + MetaScannerVisitor visitor = new MetaScannerVisitor() { + public boolean processRow(RowResult rowResult) throws IOException { + HRegionInfo info = Writables.getHRegionInfo( + rowResult.get(HConstants.COL_REGIONINFO)); + + if (!(Bytes.equals(info.getTableDesc().getName(), getTableName()))) { + return false; + } + + HServerAddress server = new HServerAddress(); + Cell c = rowResult.get(HConstants.COL_SERVER); + if (c != null && c.getValue() != null && c.getValue().length > 0) { + String address = Bytes.toString(c.getValue()); + server = new HServerAddress(address); + } + + if (!(info.isOffline() || info.isSplit())) { + regionMap.put(new UnmodifyableHRegionInfo(info), server); + } + return true; + } + + }; + MetaScanner.metaScan(configuration, visitor, tableName); + return regionMap; + } + + /** + * Get a single value for the specified row and column + * + * @param row row key + * @param column column name + * @return value for specified row/column + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Cell get(final Text row, final Text column) + throws IOException { + return get(row.getBytes(), column.getBytes()); + } + + /** + * Get a single value for the specified row and column + * + * @param row row key + * @param column column name + * @param numVersions - number of versions to retrieve + * @return value for specified row/column + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Cell[] get(final Text row, final Text column, int numVersions) + throws IOException { + return get(row.getBytes(), column.getBytes(), numVersions); + } + + /** + * Get a single value for the specified row and column + * + * @param row row key + * @param column column name + * @return value for specified row/column + * @throws IOException + */ + public Cell get(final String row, final String column) + throws IOException { + return get(Bytes.toBytes(row), Bytes.toBytes(column)); + } + + /** + * Get a single value for the specified row and column + * + * @param row row key + * @param column column name + * @param numVersions - number of versions to retrieve + * @return value for specified row/column + * @throws IOException + */ + public Cell[] get(final String row, final String column, int numVersions) + throws IOException { + return get(Bytes.toBytes(row), Bytes.toBytes(column), numVersions); + } + + /** + * Get a single value for the specified row and column + * + * @param row row key + * @param column column name + * @return value for specified row/column + * @throws IOException + */ + public Cell get(final byte [] row, final byte [] column) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Cell call() throws IOException { + return server.get(location.getRegionInfo().getRegionName(), row, + column); + } + } + ); + } + + /** + * Get the specified number of versions of the specified row and column + * @param row row key + * @param column column name + * @param numVersions number of versions to retrieve + * @return Array of Cells. + * @throws IOException + */ + public Cell[] get(final byte [] row, final byte [] column, + final int numVersions) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Cell[] call() throws IOException { + return server.get(location.getRegionInfo().getRegionName(), row, + column, numVersions); + } + } + ); + } + + /** + * Get the specified number of versions of the specified row and column with + * the specified timestamp. + * + * @param row - row key + * @param column - column name + * @param timestamp - timestamp + * @param numVersions - number of versions to retrieve + * @return - array of values that match the above criteria + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Cell[] get(final Text row, final Text column, + final long timestamp, final int numVersions) + throws IOException { + return get(row.getBytes(), column.getBytes(), timestamp, numVersions); + } + + /** + * Get the specified number of versions of the specified row and column with + * the specified timestamp. + * + * @param row - row key + * @param column - column name + * @param timestamp - timestamp + * @param numVersions - number of versions to retrieve + * @return - array of values that match the above criteria + * @throws IOException + */ + public Cell[] get(final String row, final String column, + final long timestamp, final int numVersions) + throws IOException { + return get(Bytes.toBytes(row), Bytes.toBytes(column), timestamp, numVersions); + } + + /** + * Get the specified number of versions of the specified row and column with + * the specified timestamp. + * + * @param row - row key + * @param column - column name + * @param timestamp - timestamp + * @param numVersions - number of versions to retrieve + * @return - array of values that match the above criteria + * @throws IOException + */ + public Cell[] get(final byte [] row, final byte [] column, + final long timestamp, final int numVersions) + throws IOException { + Cell[] values = null; + values = connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Cell[] call() throws IOException { + return server.get(location.getRegionInfo().getRegionName(), row, + column, timestamp, numVersions); + } + } + ); + + if (values != null) { + ArrayList cellValues = new ArrayList(); + for (int i = 0 ; i < values.length; i++) { + cellValues.add(values[i]); + } + return cellValues.toArray(new Cell[values.length]); + } + return null; + } + + /** + * Get all the data for the specified row at the latest timestamp + * + * @param row row key + * @return RowResult is empty if row does not exist. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public RowResult getRow(final Text row) throws IOException { + return getRow(row.getBytes()); + } + + /** + * Get all the data for the specified row at the latest timestamp + * + * @param row row key + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final String row) throws IOException { + return getRow(Bytes.toBytes(row)); + } + + /** + * Get all the data for the specified row at the latest timestamp + * + * @param row row key + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final byte [] row) throws IOException { + return getRow(row, HConstants.LATEST_TIMESTAMP); + } + + /** + * Get all the data for the specified row at a specified timestamp + * + * @param row row key + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public RowResult getRow(final Text row, final long ts) + throws IOException { + return getRow(row.getBytes(), ts); + } + + /** + * Get all the data for the specified row at a specified timestamp + * + * @param row row key + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final String row, final long ts) + throws IOException { + return getRow(Bytes.toBytes(row), ts); + } + + /** + * Get all the data for the specified row at a specified timestamp + * + * @param row row key + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final byte [] row, final long ts) + throws IOException { + return getRow(row,null,ts); + } + + /** + * Get selected columns for the specified row at the latest timestamp + * + * @param row row key + * @param columns Array of column names and families you want to retrieve. + * @return RowResult is empty if row does not exist. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public RowResult getRow(final Text row, final Text[] columns) + throws IOException { + return getRow(row.getBytes(), Bytes.toByteArrays(columns)); + } + + /** + * Get selected columns for the specified row at the latest timestamp + * + * @param row row key + * @param columns Array of column names and families you want to retrieve. + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final String row, final String [] columns) + throws IOException { + return getRow(Bytes.toBytes(row), Bytes.toByteArrays(columns)); + } + + /** + * Get selected columns for the specified row at the latest timestamp + * + * @param row row key + * @param columns Array of column names and families you want to retrieve. + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final byte [] row, final byte [][] columns) + throws IOException { + return getRow(row, columns, HConstants.LATEST_TIMESTAMP); + } + + /** + * Get selected columns for the specified row at a specified timestamp + * + * @param row row key + * @param columns Array of column names and families you want to retrieve. + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public RowResult getRow(final Text row, final Text [] columns, + final long ts) + throws IOException { + return getRow(row.getBytes(), Bytes.toByteArrays(columns), ts); + } + + /** + * Get selected columns for the specified row at a specified timestamp + * + * @param row row key + * @param columns Array of column names and families you want to retrieve. + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final String row, final String [] columns, + final long ts) + throws IOException { + return getRow(Bytes.toBytes(row), Bytes.toByteArrays(columns), ts); + } + + /** + * Get selected columns for the specified row at a specified timestamp + * + * @param row row key + * @param columns Array of column names and families you want to retrieve. + * @param ts timestamp + * @return RowResult is empty if row does not exist. + * @throws IOException + */ + public RowResult getRow(final byte [] row, final byte [][] columns, + final long ts) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public RowResult call() throws IOException { + return server.getRow(location.getRegionInfo().getRegionName(), row, + columns, ts); + } + } + ); + } + + /** + * Get a scanner on the current table starting at first row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @return scanner + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Scanner getScanner(final Text [] columns) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), HConstants.EMPTY_START_ROW); + } + + /** + * Get a scanner on the current table starting at first row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final String [] columns) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), HConstants.EMPTY_START_ROW); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @return scanner + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Scanner getScanner(final Text [] columns, final Text startRow) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), startRow.getBytes()); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final String [] columns, final String startRow) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow)); + } + + /** + * Get a scanner on the current table starting at first row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte[][] columns) + throws IOException { + return getScanner(columns, HConstants.EMPTY_START_ROW, + HConstants.LATEST_TIMESTAMP, null); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte[][] columns, final byte [] startRow) + throws IOException { + return getScanner(columns, startRow, HConstants.LATEST_TIMESTAMP, null); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param timestamp only return results whose timestamp <= this value + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte[][] columns, final byte [] startRow, + long timestamp) + throws IOException { + return getScanner(columns, startRow, timestamp, null); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param filter a row filter using row-key regexp and/or column data filter. + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte[][] columns, final byte [] startRow, + RowFilterInterface filter) + throws IOException { + return getScanner(columns, startRow, HConstants.LATEST_TIMESTAMP, filter); + } + + /** + * Get a scanner on the current table starting at the specified row and + * ending just before stopRow. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param stopRow Row to stop scanning on. Once we hit this row we stop + * returning values; i.e. we return the row before this one but not the + * stopRow itself. + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte [][] columns, + final byte [] startRow, final byte [] stopRow) + throws IOException { + return getScanner(columns, startRow, stopRow, + HConstants.LATEST_TIMESTAMP); + } + + /** + * Get a scanner on the current table starting at the specified row and + * ending just before stopRow. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param stopRow Row to stop scanning on. Once we hit this row we stop + * returning values; i.e. we return the row before this one but not the + * stopRow itself. + * @param timestamp only return results whose timestamp <= this value + * @return scanner + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Scanner getScanner(final Text[] columns, + final Text startRow, final Text stopRow, final long timestamp) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), startRow.getBytes(), + stopRow.getBytes(), timestamp); + } + + /** + * Get a scanner on the current table starting at the specified row and + * ending just before stopRow. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param stopRow Row to stop scanning on. Once we hit this row we stop + * returning values; i.e. we return the row before this one but not the + * stopRow itself. + * @param timestamp only return results whose timestamp <= this value + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final String [] columns, + final String startRow, final String stopRow, final long timestamp) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow), + Bytes.toBytes(stopRow), timestamp); + } + + /** + * Get a scanner on the current table starting at the specified row and + * ending just before stopRow. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param stopRow Row to stop scanning on. Once we hit this row we stop + * returning values; i.e. we return the row before this one but not the + * stopRow itself. + * @param timestamp only return results whose timestamp <= this value + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte [][] columns, + final byte [] startRow, final byte [] stopRow, final long timestamp) + throws IOException { + return getScanner(columns, startRow, timestamp, + new WhileMatchRowFilter(new StopRowFilter(stopRow))); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param timestamp only return results whose timestamp <= this value + * @param filter a row filter using row-key regexp and/or column data filter. + * @return scanner + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public Scanner getScanner(Text[] columns, + Text startRow, long timestamp, RowFilterInterface filter) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), startRow.getBytes(), + timestamp, filter); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param timestamp only return results whose timestamp <= this value + * @param filter a row filter using row-key regexp and/or column data filter. + * @return scanner + * @throws IOException + */ + public Scanner getScanner(String[] columns, + String startRow, long timestamp, RowFilterInterface filter) + throws IOException { + return getScanner(Bytes.toByteArrays(columns), Bytes.toBytes(startRow), + timestamp, filter); + } + + /** + * Get a scanner on the current table starting at the specified row. + * Return the specified columns. + * + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex in the column qualifier. A column qualifier is judged to + * be a regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row in table to scan + * @param timestamp only return results whose timestamp <= this value + * @param filter a row filter using row-key regexp and/or column data filter. + * @return scanner + * @throws IOException + */ + public Scanner getScanner(final byte [][] columns, + final byte [] startRow, long timestamp, RowFilterInterface filter) + throws IOException { + return new ClientScanner(columns, startRow, timestamp, filter); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @throws IOException + */ + public void deleteAll(final byte [] row) throws IOException { + deleteAll(row, null); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public void deleteAll(final Text row) throws IOException { + deleteAll(row, null); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @throws IOException + */ + public void deleteAll(final String row) throws IOException { + deleteAll(row, null); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @param column column to be deleted + * @throws IOException + */ + public void deleteAll(final byte [] row, final byte [] column) + throws IOException { + deleteAll(row, column, HConstants.LATEST_TIMESTAMP); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @param ts Delete all cells of the same timestamp or older. + * @throws IOException + */ + public void deleteAll(final byte [] row, final long ts) + throws IOException { + deleteAll(row, null, ts); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @param ts Delete all cells of the same timestamp or older. + * @throws IOException + */ + public void deleteAll(final String row, final long ts) + throws IOException { + deleteAll(row, null, ts); + } + + /** + * Completely delete the row's cells. + * + * @param row Key of the row you want to completely delete. + * @param ts Delete all cells of the same timestamp or older. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public void deleteAll(final Text row, final long ts) + throws IOException { + deleteAll(row, null, ts); + } + + /** + * Delete all cells that match the passed row and column. + * @param row Row to update + * @param column name of column whose value is to be deleted + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public void deleteAll(final Text row, final Text column) throws IOException { + deleteAll(row, column, HConstants.LATEST_TIMESTAMP); + } + + /** + * Delete all cells that match the passed row and column. + * @param row Row to update + * @param column name of column whose value is to be deleted + * @throws IOException + */ + public void deleteAll(final String row, final String column) + throws IOException { + deleteAll(row, column, HConstants.LATEST_TIMESTAMP); + } + + /** + * Delete all cells that match the passed row and column and whose + * timestamp is equal-to or older than the passed timestamp. + * @param row Row to update + * @param column name of column whose value is to be deleted + * @param ts Delete all cells of the same timestamp or older. + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public void deleteAll(final Text row, final Text column, final long ts) + throws IOException { + deleteAll(row.getBytes(), column.getBytes(), ts); + } + + /** + * Delete all cells that match the passed row and column and whose + * timestamp is equal-to or older than the passed timestamp. + * @param row Row to update + * @param column name of column whose value is to be deleted + * @param ts Delete all cells of the same timestamp or older. + * @throws IOException + */ + public void deleteAll(final String row, final String column, final long ts) + throws IOException { + deleteAll(Bytes.toBytes(row), + column != null? Bytes.toBytes(column): null, ts); + } + + /** + * Delete all cells that match the passed row and column and whose + * timestamp is equal-to or older than the passed timestamp. + * @param row Row to update + * @param column name of column whose value is to be deleted + * @param ts Delete all cells of the same timestamp or older. + * @throws IOException + */ + public void deleteAll(final byte [] row, final byte [] column, final long ts) + throws IOException { + connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Boolean call() throws IOException { + if (column != null) { + this.server.deleteAll(location.getRegionInfo().getRegionName(), + row, column, ts); + } else { + this.server.deleteAll(location.getRegionInfo().getRegionName(), + row, ts); + } + return null; + } + } + ); + } + + /** + * Delete all cells for a row with matching column family at all timestamps. + * + * @param row The row to operate on + * @param family The column family to match + * @param timestamp Timestamp to match + * @throws IOException + * @deprecated Use String or byte [] overload instead + */ + public void deleteFamily(final Text row, final Text family, + final long timestamp) + throws IOException{ + deleteFamily(row.getBytes(), family.getBytes(), timestamp); + } + + /** + * Delete all cells for a row with matching column family at all timestamps. + * + * @param row The row to operate on + * @param family The column family to match + * @param timestamp Timestamp to match + * @throws IOException + */ + public void deleteFamily(final String row, final String family, + final long timestamp) + throws IOException{ + deleteFamily(Bytes.toBytes(row), Bytes.toBytes(family), timestamp); + } + + /** + * Delete all cells for a row with matching column family with timestamps + * less than or equal to timestamp. + * + * @param row The row to operate on + * @param family The column family to match + * @param timestamp Timestamp to match + * @throws IOException + */ + public void deleteFamily(final byte [] row, final byte [] family, + final long timestamp) + throws IOException { + connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public Boolean call() throws IOException { + server.deleteFamily(location.getRegionInfo().getRegionName(), row, + family, timestamp); + return null; + } + } + ); + } + + /** + * Commit a BatchUpdate to the table. + * @param batchUpdate + * @throws IOException + */ + public synchronized void commit(final BatchUpdate batchUpdate) + throws IOException { + connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, batchUpdate.getRow()) { + public Boolean call() throws IOException { + server.batchUpdate(location.getRegionInfo().getRegionName(), + batchUpdate); + return null; + } + } + ); + } + + /** + * Commit a RowsBatchUpdate to the table. + * @param batchUpdates + * @throws IOException + */ + public synchronized void commit(final List batchUpdates) + throws IOException { + for (BatchUpdate batchUpdate : batchUpdates) + commit(batchUpdate); + } + + /** + * Implements the scanner interface for the HBase client. + * If there are multiple regions in a table, this scanner will iterate + * through them all. + */ + protected class ClientScanner implements Scanner { + private final Log CLIENT_LOG = LogFactory.getLog(this.getClass()); + private byte[][] columns; + private byte [] startRow; + protected long scanTime; + @SuppressWarnings("hiding") + private boolean closed = false; + private HRegionInfo currentRegion = null; + private ScannerCallable callable = null; + protected RowFilterInterface filter; + + protected ClientScanner(final Text [] columns, final Text startRow, + long timestamp, RowFilterInterface filter) + throws IOException { + this(Bytes.toByteArrays(columns), startRow.getBytes(), timestamp, + filter); + } + + protected ClientScanner(final byte[][] columns, final byte [] startRow, + final long timestamp, final RowFilterInterface filter) + throws IOException { + if (CLIENT_LOG.isDebugEnabled()) { + CLIENT_LOG.debug("Creating scanner over " + Bytes.toString(getTableName()) + + " starting at key '" + Bytes.toString(startRow) + "'"); + } + // save off the simple parameters + this.columns = columns; + this.startRow = startRow; + this.scanTime = timestamp; + + // save the filter, and make sure that the filter applies to the data + // we're expecting to pull back + this.filter = filter; + if (filter != null) { + filter.validate(columns); + } + nextScanner(); + } + + protected byte[][] getColumns() { + return columns; + } + + protected long getTimestamp() { + return scanTime; + } + + protected RowFilterInterface getFilter() { + return filter; + } + + /* + * Gets a scanner for the next region. + * Returns false if there are no more scanners. + */ + private boolean nextScanner() throws IOException { + // Close the previous scanner if it's open + if (this.callable != null) { + this.callable.setClose(); + getConnection().getRegionServerWithRetries(callable); + this.callable = null; + } + + // if we're at the end of the table, then close and return false + // to stop iterating + if (currentRegion != null) { + if (CLIENT_LOG.isDebugEnabled()) { + CLIENT_LOG.debug("Advancing forward from region " + currentRegion); + } + + byte [] endKey = currentRegion.getEndKey(); + if (endKey == null || + Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY) || + filterSaysStop(endKey)) { + close(); + return false; + } + } + + HRegionInfo oldRegion = this.currentRegion; + byte [] localStartKey = oldRegion == null? startRow: oldRegion.getEndKey(); + + if (CLIENT_LOG.isDebugEnabled()) { + CLIENT_LOG.debug("Advancing internal scanner to startKey at '" + + Bytes.toString(localStartKey) + "'"); + } + + try { + callable = getScannerCallable(localStartKey); + // open a scanner on the region server starting at the + // beginning of the region + getConnection().getRegionServerWithRetries(callable); + currentRegion = callable.getHRegionInfo(); + } catch (IOException e) { + close(); + throw e; + } + return true; + } + + protected ScannerCallable getScannerCallable(byte [] localStartKey) { + return new ScannerCallable(getConnection(), getTableName(), columns, + localStartKey, scanTime, filter); + } + + /** + * @param endKey + * @return Returns true if the passed region endkey is judged beyond + * filter. + */ + private boolean filterSaysStop(final byte [] endKey) { + if (this.filter == null) { + return false; + } + // Let the filter see current row. + this.filter.filterRowKey(endKey); + return this.filter.filterAllRemaining(); + } + + /** {@inheritDoc} */ + public RowResult next() throws IOException { + if (this.closed) { + return null; + } + RowResult values = null; + do { + values = getConnection().getRegionServerWithRetries(callable); + } while ((values == null || values.size() == 0) && nextScanner()); + + if (values != null && values.size() != 0) { + return values; + } + return null; + } + + /** + * {@inheritDoc} + */ + public void close() { + if (callable != null) { + callable.setClose(); + try { + getConnection().getRegionServerWithRetries(callable); + } catch (IOException e) { + // We used to catch this error, interpret, and rethrow. However, we + // have since decided that it's not nice for a scanner's close to + // throw exceptions. Chances are it was just an UnknownScanner + // exception due to lease time out. + } + callable = null; + } + closed = true; + } + + /** {@inheritDoc} */ + public Iterator iterator() { + return new Iterator() { + // The next RowResult, possibly pre-read + RowResult next = null; + + // return true if there is another item pending, false if there isn't. + // this method is where the actual advancing takes place, but you need + // to call next() to consume it. hasNext() will only advance if there + // isn't a pending next(). + public boolean hasNext() { + if (next == null) { + try { + next = ClientScanner.this.next(); + return next != null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return true; + } + + // get the pending next item and advance the iterator. returns null if + // there is no next item. + public RowResult next() { + // since hasNext() does the real advancing, we call this to determine + // if there is a next before proceeding. + if (!hasNext()) { + return null; + } + + // if we get to here, then hasNext() has given us an item to return. + // we want to return the item and then null out the next pointer, so + // we use a temporary variable. + RowResult temp = next; + next = null; + return temp; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + } +} diff --git a/src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java b/src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java index e3a00e3ead2..0aed6af9911 100644 --- a/src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java +++ b/src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java @@ -1,210 +1,210 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * 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.hadoop.hbase.ipc; - -import java.io.IOException; - -import org.apache.hadoop.hbase.filter.RowFilterInterface; -import org.apache.hadoop.hbase.io.BatchUpdate; -import org.apache.hadoop.hbase.io.Cell; -import org.apache.hadoop.hbase.io.RowResult; - -import org.apache.hadoop.ipc.VersionedProtocol; -import org.apache.hadoop.hbase.HRegionInfo; -import org.apache.hadoop.hbase.NotServingRegionException; - -/** - * Clients interact with HRegionServers using a handle to the HRegionInterface. - */ -public interface HRegionInterface extends VersionedProtocol { - /** - * Protocol version. - * Upped to 3 when we went from Text to byte arrays for row and column names. - */ - public static final long versionID = 3L; - - /** - * Get metainfo about an HRegion - * - * @param regionName name of the region - * @return HRegionInfo object for region - * @throws NotServingRegionException - */ - public HRegionInfo getRegionInfo(final byte [] regionName) - throws NotServingRegionException; - - /** - * Retrieve a single value from the specified region for the specified row - * and column keys - * - * @param regionName name of region - * @param row row key - * @param column column key - * @return alue for that region/row/column - * @throws IOException - */ - public Cell get(final byte [] regionName, final byte [] row, final byte [] column) - throws IOException; - - /** - * Get the specified number of versions of the specified row and column - * - * @param regionName region name - * @param row row key - * @param column column key - * @param numVersions number of versions to return - * @return array of values - * @throws IOException - */ - public Cell[] get(final byte [] regionName, final byte [] row, - final byte [] column, final int numVersions) - throws IOException; - - /** - * Get the specified number of versions of the specified row and column with - * the specified timestamp. - * - * @param regionName region name - * @param row row key - * @param column column key - * @param timestamp timestamp - * @param numVersions number of versions to return - * @return array of values - * @throws IOException - */ - public Cell[] get(final byte [] regionName, final byte [] row, - final byte [] column, final long timestamp, final int numVersions) - throws IOException; - - /** - * Return all the data for the row that matches row exactly, - * or the one that immediately preceeds it. - * - * @param regionName region name - * @param row row key - * @return map of values - * @throws IOException - */ - public RowResult getClosestRowBefore(final byte [] regionName, - final byte [] row) - throws IOException; - - /** - * Get selected columns for the specified row at a given timestamp. - * - * @param regionName region name - * @param row row key - * @return map of values - * @throws IOException - */ - public RowResult getRow(final byte [] regionName, final byte [] row, - final byte[][] columns, final long ts) - throws IOException; - - /** - * Applies a batch of updates via one RPC - * - * @param regionName name of the region to update - * @param b BatchUpdate - * @throws IOException - */ - public void batchUpdate(final byte [] regionName, final BatchUpdate b) - throws IOException; - - /** - * Delete all cells that match the passed row and column and whose - * timestamp is equal-to or older than the passed timestamp. - * - * @param regionName region name - * @param row row key - * @param column column key - * @param timestamp Delete all entries that have this timestamp or older - * @throws IOException - */ - public void deleteAll(byte [] regionName, byte [] row, byte [] column, - long timestamp) - throws IOException; - - /** - * Delete all cells that match the passed row and whose - * timestamp is equal-to or older than the passed timestamp. - * - * @param regionName region name - * @param row row key - * @param timestamp Delete all entries that have this timestamp or older - * @throws IOException - */ - public void deleteAll(byte [] regionName, byte [] row, long timestamp) - throws IOException; - - /** - * Delete all cells for a row with matching column family with timestamps - * less than or equal to timestamp. - * - * @param regionName The name of the region to operate on - * @param row The row to operate on - * @param family The column family to match - * @param timestamp Timestamp to match - */ - public void deleteFamily(byte [] regionName, byte [] row, byte [] family, - long timestamp) - throws IOException; - - - // - // remote scanner interface - // - - /** - * Opens a remote scanner with a RowFilter. - * - * @param regionName name of region to scan - * @param columns columns to scan. If column name is a column family, all - * columns of the specified column family are returned. Its also possible - * to pass a regex for column family name. A column name is judged to be - * regex if it contains at least one of the following characters: - * \+|^&*$[]]}{)(. - * @param startRow starting row to scan - * @param timestamp only return values whose timestamp is <= this value - * @param filter RowFilter for filtering results at the row-level. - * - * @return scannerId scanner identifier used in other calls - * @throws IOException - */ - public long openScanner(final byte [] regionName, final byte [][] columns, - final byte [] startRow, long timestamp, RowFilterInterface filter) - throws IOException; - - /** - * Get the next set of values - * @param scannerId clientId passed to openScanner - * @return map of values - * @throws IOException - */ - public RowResult next(long scannerId) throws IOException; - - /** - * Close a scanner - * - * @param scannerId the scanner id returned by openScanner - * @throws IOException - */ - public void close(long scannerId) throws IOException; +/** + * Copyright 2007 The Apache Software Foundation + * + * 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.hadoop.hbase.ipc; + +import java.io.IOException; + +import org.apache.hadoop.hbase.filter.RowFilterInterface; +import org.apache.hadoop.hbase.io.BatchUpdate; +import org.apache.hadoop.hbase.io.Cell; +import org.apache.hadoop.hbase.io.RowResult; + +import org.apache.hadoop.ipc.VersionedProtocol; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.NotServingRegionException; + +/** + * Clients interact with HRegionServers using a handle to the HRegionInterface. + */ +public interface HRegionInterface extends VersionedProtocol { + /** + * Protocol version. + * Upped to 3 when we went from Text to byte arrays for row and column names. + */ + public static final long versionID = 3L; + + /** + * Get metainfo about an HRegion + * + * @param regionName name of the region + * @return HRegionInfo object for region + * @throws NotServingRegionException + */ + public HRegionInfo getRegionInfo(final byte [] regionName) + throws NotServingRegionException; + + /** + * Retrieve a single value from the specified region for the specified row + * and column keys + * + * @param regionName name of region + * @param row row key + * @param column column key + * @return alue for that region/row/column + * @throws IOException + */ + public Cell get(final byte [] regionName, final byte [] row, final byte [] column) + throws IOException; + + /** + * Get the specified number of versions of the specified row and column + * + * @param regionName region name + * @param row row key + * @param column column key + * @param numVersions number of versions to return + * @return array of values + * @throws IOException + */ + public Cell[] get(final byte [] regionName, final byte [] row, + final byte [] column, final int numVersions) + throws IOException; + + /** + * Get the specified number of versions of the specified row and column with + * the specified timestamp. + * + * @param regionName region name + * @param row row key + * @param column column key + * @param timestamp timestamp + * @param numVersions number of versions to return + * @return array of values + * @throws IOException + */ + public Cell[] get(final byte [] regionName, final byte [] row, + final byte [] column, final long timestamp, final int numVersions) + throws IOException; + + /** + * Return all the data for the row that matches row exactly, + * or the one that immediately preceeds it. + * + * @param regionName region name + * @param row row key + * @return map of values + * @throws IOException + */ + public RowResult getClosestRowBefore(final byte [] regionName, + final byte [] row) + throws IOException; + + /** + * Get selected columns for the specified row at a given timestamp. + * + * @param regionName region name + * @param row row key + * @return map of values + * @throws IOException + */ + public RowResult getRow(final byte [] regionName, final byte [] row, + final byte[][] columns, final long ts) + throws IOException; + + /** + * Applies a batch of updates via one RPC + * + * @param regionName name of the region to update + * @param b BatchUpdate + * @throws IOException + */ + public void batchUpdate(final byte [] regionName, final BatchUpdate b) + throws IOException; + + /** + * Delete all cells that match the passed row and column and whose + * timestamp is equal-to or older than the passed timestamp. + * + * @param regionName region name + * @param row row key + * @param column column key + * @param timestamp Delete all entries that have this timestamp or older + * @throws IOException + */ + public void deleteAll(byte [] regionName, byte [] row, byte [] column, + long timestamp) + throws IOException; + + /** + * Delete all cells that match the passed row and whose + * timestamp is equal-to or older than the passed timestamp. + * + * @param regionName region name + * @param row row key + * @param timestamp Delete all entries that have this timestamp or older + * @throws IOException + */ + public void deleteAll(byte [] regionName, byte [] row, long timestamp) + throws IOException; + + /** + * Delete all cells for a row with matching column family with timestamps + * less than or equal to timestamp. + * + * @param regionName The name of the region to operate on + * @param row The row to operate on + * @param family The column family to match + * @param timestamp Timestamp to match + */ + public void deleteFamily(byte [] regionName, byte [] row, byte [] family, + long timestamp) + throws IOException; + + + // + // remote scanner interface + // + + /** + * Opens a remote scanner with a RowFilter. + * + * @param regionName name of region to scan + * @param columns columns to scan. If column name is a column family, all + * columns of the specified column family are returned. Its also possible + * to pass a regex for column family name. A column name is judged to be + * regex if it contains at least one of the following characters: + * \+|^&*$[]]}{)(. + * @param startRow starting row to scan + * @param timestamp only return values whose timestamp is <= this value + * @param filter RowFilter for filtering results at the row-level. + * + * @return scannerId scanner identifier used in other calls + * @throws IOException + */ + public long openScanner(final byte [] regionName, final byte [][] columns, + final byte [] startRow, long timestamp, RowFilterInterface filter) + throws IOException; + + /** + * Get the next set of values + * @param scannerId clientId passed to openScanner + * @return map of values + * @throws IOException + */ + public RowResult next(long scannerId) throws IOException; + + /** + * Close a scanner + * + * @param scannerId the scanner id returned by openScanner + * @throws IOException + */ + public void close(long scannerId) throws IOException; } \ No newline at end of file diff --git a/src/test/org/apache/hadoop/hbase/client/TestBatchUpdate.java b/src/test/org/apache/hadoop/hbase/client/TestBatchUpdate.java index 8534a2a5196..aca846f1b49 100644 --- a/src/test/org/apache/hadoop/hbase/client/TestBatchUpdate.java +++ b/src/test/org/apache/hadoop/hbase/client/TestBatchUpdate.java @@ -1,151 +1,151 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * 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.hadoop.hbase.client; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Map; - -import org.apache.hadoop.hbase.HBaseClusterTestCase; -import org.apache.hadoop.hbase.HColumnDescriptor; -import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.io.BatchUpdate; -import org.apache.hadoop.hbase.io.Cell; -import org.apache.hadoop.hbase.io.RowResult; -import org.apache.hadoop.hbase.util.Bytes; - -/** - * Test batch updates - */ -public class TestBatchUpdate extends HBaseClusterTestCase { - private static final String CONTENTS_STR = "contents:"; - private static final byte [] CONTENTS = Bytes.toBytes(CONTENTS_STR); - private static final String SMALLFAM_STR = "smallfam:"; - private static final byte [] SMALLFAM = Bytes.toBytes(SMALLFAM_STR); - private static final int SMALL_LENGTH = 1; - private static final int NB_BATCH_ROWS = 10; - private byte[] value; - private byte[] smallValue; - - private HTableDescriptor desc = null; - private HTable table = null; - - /** - * @throws UnsupportedEncodingException - */ - public TestBatchUpdate() throws UnsupportedEncodingException { - super(); - value = "abcd".getBytes(HConstants.UTF8_ENCODING); - smallValue = "a".getBytes(HConstants.UTF8_ENCODING); - } - - /** - * {@inheritDoc} - */ - @Override - public void setUp() throws Exception { - super.setUp(); - this.desc = new HTableDescriptor("test"); - desc.addFamily(new HColumnDescriptor(CONTENTS_STR)); - desc.addFamily(new HColumnDescriptor(SMALLFAM, - HColumnDescriptor.DEFAULT_VERSIONS, - HColumnDescriptor.DEFAULT_COMPRESSION, - HColumnDescriptor.DEFAULT_IN_MEMORY, - HColumnDescriptor.DEFAULT_BLOCKCACHE, SMALL_LENGTH, - HColumnDescriptor.DEFAULT_TTL, HColumnDescriptor.DEFAULT_BLOOMFILTER)); - HBaseAdmin admin = new HBaseAdmin(conf); - admin.createTable(desc); - table = new HTable(conf, desc.getName()); - } - - /** - * @throws IOException - */ - public void testBatchUpdate() throws IOException { - BatchUpdate bu = new BatchUpdate("row1"); - bu.put(CONTENTS, value); - bu.delete(CONTENTS); - table.commit(bu); - - bu = new BatchUpdate("row2"); - bu.put(CONTENTS, value); - table.commit(bu); - - byte [][] columns = { CONTENTS }; - Scanner scanner = table.getScanner(columns, HConstants.EMPTY_START_ROW); - for (RowResult r : scanner) { - for(Map.Entry e: r.entrySet()) { - System.out.println(r.getRow() + ": row: " + e.getKey() + " value: " + - new String(e.getValue().getValue(), HConstants.UTF8_ENCODING)); - } - } - } - - public void testBatchUpdateMaxLength() { - // Test for a single good value - BatchUpdate batchUpdate = new BatchUpdate("row1"); - batchUpdate.put(SMALLFAM, value); - try { - table.commit(batchUpdate); - fail("Value is too long, should throw exception"); - } catch (IOException e) { - // This is expected - } - // Try to see if it's still inserted - try { - Cell cell = table.get("row1", SMALLFAM_STR); - assertNull(cell); - } catch (IOException e) { - e.printStackTrace(); - fail("This is unexpected"); - } - // Try to put a good value - batchUpdate = new BatchUpdate("row1"); - batchUpdate.put(SMALLFAM, smallValue); - try { - table.commit(batchUpdate); - } catch (IOException e) { - fail("Value is long enough, should not throw exception"); - } - } - - public void testRowsBatchUpdate() { - ArrayList rowsUpdate = new ArrayList(); - for(int i = 0; i < NB_BATCH_ROWS; i++) { - BatchUpdate batchUpdate = new BatchUpdate("row"+i); - batchUpdate.put(CONTENTS, value); - rowsUpdate.add(batchUpdate); - } - try { - table.commit(rowsUpdate); - - byte [][] columns = { CONTENTS }; - Scanner scanner = table.getScanner(columns, HConstants.EMPTY_START_ROW); - int nbRows = 0; - for(RowResult row : scanner) - nbRows++; - assertEquals(NB_BATCH_ROWS, nbRows); - } catch (IOException e) { - fail("This is unexpected : " + e); - } - } -} +/** + * Copyright 2007 The Apache Software Foundation + * + * 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.hadoop.hbase.client; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Map; + +import org.apache.hadoop.hbase.HBaseClusterTestCase; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.io.BatchUpdate; +import org.apache.hadoop.hbase.io.Cell; +import org.apache.hadoop.hbase.io.RowResult; +import org.apache.hadoop.hbase.util.Bytes; + +/** + * Test batch updates + */ +public class TestBatchUpdate extends HBaseClusterTestCase { + private static final String CONTENTS_STR = "contents:"; + private static final byte [] CONTENTS = Bytes.toBytes(CONTENTS_STR); + private static final String SMALLFAM_STR = "smallfam:"; + private static final byte [] SMALLFAM = Bytes.toBytes(SMALLFAM_STR); + private static final int SMALL_LENGTH = 1; + private static final int NB_BATCH_ROWS = 10; + private byte[] value; + private byte[] smallValue; + + private HTableDescriptor desc = null; + private HTable table = null; + + /** + * @throws UnsupportedEncodingException + */ + public TestBatchUpdate() throws UnsupportedEncodingException { + super(); + value = "abcd".getBytes(HConstants.UTF8_ENCODING); + smallValue = "a".getBytes(HConstants.UTF8_ENCODING); + } + + /** + * {@inheritDoc} + */ + @Override + public void setUp() throws Exception { + super.setUp(); + this.desc = new HTableDescriptor("test"); + desc.addFamily(new HColumnDescriptor(CONTENTS_STR)); + desc.addFamily(new HColumnDescriptor(SMALLFAM, + HColumnDescriptor.DEFAULT_VERSIONS, + HColumnDescriptor.DEFAULT_COMPRESSION, + HColumnDescriptor.DEFAULT_IN_MEMORY, + HColumnDescriptor.DEFAULT_BLOCKCACHE, SMALL_LENGTH, + HColumnDescriptor.DEFAULT_TTL, HColumnDescriptor.DEFAULT_BLOOMFILTER)); + HBaseAdmin admin = new HBaseAdmin(conf); + admin.createTable(desc); + table = new HTable(conf, desc.getName()); + } + + /** + * @throws IOException + */ + public void testBatchUpdate() throws IOException { + BatchUpdate bu = new BatchUpdate("row1"); + bu.put(CONTENTS, value); + bu.delete(CONTENTS); + table.commit(bu); + + bu = new BatchUpdate("row2"); + bu.put(CONTENTS, value); + table.commit(bu); + + byte [][] columns = { CONTENTS }; + Scanner scanner = table.getScanner(columns, HConstants.EMPTY_START_ROW); + for (RowResult r : scanner) { + for(Map.Entry e: r.entrySet()) { + System.out.println(r.getRow() + ": row: " + e.getKey() + " value: " + + new String(e.getValue().getValue(), HConstants.UTF8_ENCODING)); + } + } + } + + public void testBatchUpdateMaxLength() { + // Test for a single good value + BatchUpdate batchUpdate = new BatchUpdate("row1"); + batchUpdate.put(SMALLFAM, value); + try { + table.commit(batchUpdate); + fail("Value is too long, should throw exception"); + } catch (IOException e) { + // This is expected + } + // Try to see if it's still inserted + try { + Cell cell = table.get("row1", SMALLFAM_STR); + assertNull(cell); + } catch (IOException e) { + e.printStackTrace(); + fail("This is unexpected"); + } + // Try to put a good value + batchUpdate = new BatchUpdate("row1"); + batchUpdate.put(SMALLFAM, smallValue); + try { + table.commit(batchUpdate); + } catch (IOException e) { + fail("Value is long enough, should not throw exception"); + } + } + + public void testRowsBatchUpdate() { + ArrayList rowsUpdate = new ArrayList(); + for(int i = 0; i < NB_BATCH_ROWS; i++) { + BatchUpdate batchUpdate = new BatchUpdate("row"+i); + batchUpdate.put(CONTENTS, value); + rowsUpdate.add(batchUpdate); + } + try { + table.commit(rowsUpdate); + + byte [][] columns = { CONTENTS }; + Scanner scanner = table.getScanner(columns, HConstants.EMPTY_START_ROW); + int nbRows = 0; + for(RowResult row : scanner) + nbRows++; + assertEquals(NB_BATCH_ROWS, nbRows); + } catch (IOException e) { + fail("This is unexpected : " + e); + } + } +}