Index: src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 684093) +++ src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -1295,7 +1295,64 @@ getRegion(regionName).deleteFamily(row, family, timestamp); } + /** {@inheritDoc} */ + public byte [] incrementColumnValue(byte [] regionName, byte [] row, + byte [] column) + throws IOException { + checkOpen(); + NullPointerException npe = null; + if(regionName == null) { + npe = new NullPointerException("regionName is null"); + } else if(row == null) { + npe = new NullPointerException("row is null"); + } else if(column == null) { + npe = new NullPointerException("column is null"); + } + if(npe != null) { + IOException io = new IOException( + "Invalid arguments to incrementColumnValue"); + io.initCause(npe); + throw io; + } + requestCount.incrementAndGet(); + try { + HRegion region = getRegion(regionName); + return region.incrementColumnValue(row,column); + } catch (IOException e) { + checkFileSystem(); + throw e; + } + } + /** {@inheritDoc} */ + public byte [] incrementFamilyColumn(byte [] regionName, byte [] row, + byte [] family) + throws IOException { + checkOpen(); + NullPointerException npe = null; + if(regionName == null) { + npe = new NullPointerException("regionName is null"); + } else if(row == null) { + npe = new NullPointerException("row is null"); + } else if(family == null) { + npe = new NullPointerException("family is null"); + } + if(npe != null) { + IOException io = new IOException( + "Invalid arguments to incrementFamilyColumn"); + io.initCause(npe); + throw io; + } + requestCount.incrementAndGet(); + try { + HRegion region = getRegion(regionName); + return region.incrementFamilyColumn(row,family); + } catch (IOException e) { + checkFileSystem(); + throw e; + } + } + /** * @return Info on this server. */ Index: src/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- src/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 684093) +++ src/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -1547,6 +1547,72 @@ } /** + * @param row + * @param column + * @throws IOException + */ + public byte [] incrementColumnValue(final byte [] row, final byte [] column) + throws IOException { + Integer lid = obtainRowLock(row); + Cell cell = get(row,column); + byte [] value = cell.getValue(); + incrementBytes(value); + BatchUpdate b = new BatchUpdate(row); + b.put(column,value); + batchUpdate(b,lid); + releaseRowLock(lid); + return value; + } + + /** + * @param row + * @param family + * @throws IOException + */ + public byte [] incrementFamilyColumn(final byte [] row, final byte [] family) + throws IOException { + Integer lid = obtainRowLock(row); + byte[][] scancols = new byte[1][]; + scancols[0] = family; + Set columnSet = new TreeSet(Bytes.BYTES_COMPARATOR); + columnSet.addAll(Arrays.asList(scancols)); + Map map = getFull(row, columnSet, + HConstants.LATEST_TIMESTAMP, lid); + Set> cols = map.entrySet(); + Iterator> it = cols.iterator(); + Map.Entry entry = it.next(); + byte [] column = (byte [])entry.getKey(); + Cell cell = (Cell)entry.getValue(); + /* Remove previous column */ + deleteAll(row,column,HConstants.LATEST_TIMESTAMP,lid); + /* Increment and insert incremented column */ + incrementBytes(column); + BatchUpdate b = new BatchUpdate(row); + b.put(column,cell.getValue()); + batchUpdate(b,lid); + releaseRowLock(lid); + return column; + } + + /** + * Helper functions to perform byte increments. + * @param value + * @return incrementedValue + */ + private void incrementBytes(byte [] value) { + incrementBytes(value,value.length-1); + } + + private void incrementBytes(byte [] value, int pos) { + if(pos > 0 && (value[pos]+256) % 256 == 255) { + value[0] = 0; + incrementBytes(value,pos-1); + } else { + value[pos] = (byte)(value[pos]+1); + } + } + + /** * @throws IOException Throws exception if region is in read-only mode. */ protected void checkReadOnly() throws IOException { Index: src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java =================================================================== --- src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java (revision 684093) +++ src/java/org/apache/hadoop/hbase/ipc/HRegionInterface.java (working copy) @@ -207,4 +207,28 @@ * @throws IOException */ public void close(long scannerId) throws IOException; + + /** + * Increment a column value + * + * @param row + * @param column + * @return new incremented column value + * @throws IOException + */ + public byte [] incrementColumnValue(final byte [] regionName, final byte [] row, + final byte [] column) + throws IOException; + + /** + * Increment the column in the specified family + * + * @param row + * @param family + * @return new incremented column + * @throws IOException + */ + public byte [] incrementFamilyColumn(final byte [] regionName, final byte [] row, + final byte [] family) + throws IOException; } \ No newline at end of file Index: src/java/org/apache/hadoop/hbase/client/HTable.java =================================================================== --- src/java/org/apache/hadoop/hbase/client/HTable.java (revision 684093) +++ src/java/org/apache/hadoop/hbase/client/HTable.java (working copy) @@ -1201,7 +1201,45 @@ commit(batchUpdate); } + /** + * Get current value for column, increment it, insert new version + * @param row + * @param column + * @return newValue + * @throws IOException + */ + public byte [] incrementColumnValue(final byte [] row, final byte [] column) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public byte [] call() throws IOException { + return server.incrementColumnValue( + location.getRegionInfo().getRegionName(),row,column); + } + } + ); + } + /** + * Get current value for column, increment it, insert new version, remove old + * @param row + * @param family + * @return newColumn + * @throws IOException + */ + public byte [] incrementFamilyColumn(final byte [] row, final byte [] family) + throws IOException { + return connection.getRegionServerWithRetries( + new ServerCallable(connection, tableName, row) { + public byte [] call() throws IOException { + return server.incrementFamilyColumn( + location.getRegionInfo().getRegionName(),row,family); + } + } + ); + } + + /** * Implements the scanner interface for the HBase client. * If there are multiple regions in a table, this scanner will iterate * through them all.