Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/Store.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/Store.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/Store.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/Store.java Thu Jul 30 05:35:05 2009 @@ -95,7 +95,7 @@ protected final MemStore memstore; // This stores directory in the filesystem. private final Path homedir; - private final HRegionInfo regioninfo; + private final HRegion region; private final HColumnDescriptor family; final FileSystem fs; private final HBaseConfiguration conf; @@ -144,7 +144,7 @@ * Constructor * @param basedir qualified path under which the region directory lives; * generally the table subdirectory - * @param info HRegionInfo for this region + * @param region * @param family HColumnDescriptor for this column * @param fs file system object * @param reconstructionLog existing log file to apply if any @@ -154,13 +154,14 @@ * failed. Can be null. * @throws IOException */ - protected Store(Path basedir, HRegionInfo info, HColumnDescriptor family, + protected Store(Path basedir, HRegion region, HColumnDescriptor family, FileSystem fs, Path reconstructionLog, HBaseConfiguration conf, final Progressable reporter) - throws IOException { + throws IOException { + HRegionInfo info = region.regionInfo; this.homedir = getStoreHomedir(basedir, info.getEncodedName(), family.getName()); - this.regioninfo = info; + this.region = region; this.family = family; this.fs = fs; this.conf = conf; @@ -294,6 +295,7 @@ // TODO: This could grow large and blow heap out. Need to get it into // general memory usage accounting. long maxSeqIdInLog = -1; + long firstSeqIdInLog = -1; // TODO: Move this memstoring over into MemStore. KeyValueSkipListSet reconstructedCache = new KeyValueSkipListSet(this.comparator); @@ -308,6 +310,9 @@ int reportInterval = this.conf.getInt("hbase.hstore.report.interval.edits", 2000); while (logReader.next(key, val)) { + if (firstSeqIdInLog == -1) { + firstSeqIdInLog = key.getLogSeqNum(); + } maxSeqIdInLog = Math.max(maxSeqIdInLog, key.getLogSeqNum()); if (key.getLogSeqNum() <= maxSeqID) { skippedEdits++; @@ -317,7 +322,7 @@ // METACOLUMN info such as HBASE::CACHEFLUSH entries if (/* commented out for now - stack via jgray key.isTransactionEntry() || */ val.matchingFamily(HLog.METAFAMILY) || - !Bytes.equals(key.getRegionName(), regioninfo.getRegionName()) || + !Bytes.equals(key.getRegionName(), region.regionInfo.getRegionName()) || !val.matchingFamily(family.getName())) { continue; } @@ -329,10 +334,14 @@ if (reporter != null && (editsCount % reportInterval) == 0) { reporter.progress(); } + // Instantiate a new KeyValue to perform Writable on + val = new KeyValue(); } if (LOG.isDebugEnabled()) { LOG.debug("Applied " + editsCount + ", skipped " + skippedEdits + - " because sequence id <= " + maxSeqID); + "; store maxSeqID=" + maxSeqID + + ", firstSeqIdInLog=" + firstSeqIdInLog + + ", maxSeqIdInLog=" + maxSeqIdInLog); } } finally { logReader.close(); @@ -534,7 +543,7 @@ ", sequenceid=" + logCacheFlushId + ", memsize=" + StringUtils.humanReadableInt(flushed) + ", filesize=" + StringUtils.humanReadableInt(r.length()) + - " to " + this.regioninfo.getRegionNameAsString()); + " to " + this.region.regionInfo.getRegionNameAsString()); } return sf; } @@ -619,49 +628,51 @@ * thread must be able to block for long periods. * * <p>During this time, the Store can work as usual, getting values from - * MapFiles and writing new MapFiles from the memstore. + * StoreFiles and writing new StoreFiles from the memstore. * - * Existing MapFiles are not destroyed until the new compacted TreeMap is + * Existing StoreFiles are not destroyed until the new compacted StoreFile is * completely written-out to disk. * - * The compactLock prevents multiple simultaneous compactions. + * <p>The compactLock prevents multiple simultaneous compactions. * The structureLock prevents us from interfering with other write operations. * - * We don't want to hold the structureLock for the whole time, as a compact() + * <p>We don't want to hold the structureLock for the whole time, as a compact() * can be lengthy and we want to allow cache-flushes during this period. * - * @param mc True to force a major compaction regardless of - * thresholds + * @param mc True to force a major compaction regardless of thresholds * @return row to split around if a split is needed, null otherwise * @throws IOException */ StoreSize compact(final boolean mc) throws IOException { - boolean forceSplit = this.regioninfo.shouldSplit(false); + boolean forceSplit = this.region.shouldSplit(false); boolean majorcompaction = mc; synchronized (compactLock) { - long maxId = -1; // filesToCompact are sorted oldest to newest. - List<StoreFile> filesToCompact = null; - filesToCompact = new ArrayList<StoreFile>(this.storefiles.values()); - if (filesToCompact.size() <= 0) { + List<StoreFile> filesToCompact = + new ArrayList<StoreFile>(this.storefiles.values()); + if (filesToCompact.isEmpty()) { LOG.debug(this.storeNameStr + ": no store files to compact"); return null; } - // The max-sequenceID in any of the to-be-compacted TreeMaps is the - // last key of storefiles. - maxId = this.storefiles.lastKey().longValue(); + + // Max-sequenceID is the last key of the storefiles TreeMap + long maxId = this.storefiles.lastKey().longValue(); + // Check to see if we need to do a major compaction on this region. // If so, change doMajorCompaction to true to skip the incremental // compacting below. Only check if doMajorCompaction is not true. if (!majorcompaction) { majorcompaction = isMajorCompaction(filesToCompact); } + boolean references = hasReferences(filesToCompact); if (!majorcompaction && !references && (forceSplit || (filesToCompact.size() < compactionThreshold))) { return checkSplit(forceSplit); } - if (!fs.exists(this.regionCompactionDir) && !fs.mkdirs(this.regionCompactionDir)) { + + if (!fs.exists(this.regionCompactionDir) && + !fs.mkdirs(this.regionCompactionDir)) { LOG.warn("Mkdir on " + this.regionCompactionDir.toString() + " failed"); return checkSplit(forceSplit); } @@ -670,7 +681,7 @@ // selection. int countOfFiles = filesToCompact.size(); long totalSize = 0; - long[] fileSizes = new long[countOfFiles]; + long [] fileSizes = new long[countOfFiles]; long skipped = 0; int point = 0; for (int i = 0; i < countOfFiles; i++) { @@ -689,6 +700,7 @@ fileSizes[i] = len; totalSize += len; } + if (!majorcompaction && !references) { // Here we select files for incremental compaction. // The rule is: if the largest(oldest) one is more than twice the @@ -719,26 +731,17 @@ } } - // Step through them, writing to the brand-new file - HFile.Writer writer = getWriter(this.regionCompactionDir); - if (LOG.isDebugEnabled()) { - LOG.debug("Started compaction of " + filesToCompact.size() + " file(s)" + - (references? ", hasReferences=true,": " ") + " into " + - FSUtils.getPath(writer.getPath())); - } - try { - compact(writer, filesToCompact, majorcompaction); - } finally { - // Now, write out an HSTORE_LOGINFOFILE for the brand-new TreeMap. - StoreFile.appendMetadata(writer, maxId, majorcompaction); - writer.close(); - } - + // Ready to go. Have list of files to compact. + LOG.debug("Started compaction of " + filesToCompact.size() + " file(s)" + + (references? ", hasReferences=true,": " ") + " into " + + FSUtils.getPath(this.regionCompactionDir) + ", seqid=" + maxId); + HFile.Writer writer = compact(filesToCompact, majorcompaction, maxId); // Move the compaction into place. - completeCompaction(filesToCompact, writer); + StoreFile sf = completeCompaction(filesToCompact, writer); if (LOG.isDebugEnabled()) { LOG.debug("Completed" + (majorcompaction? " major ": " ") + "compaction of " + this.storeNameStr + + "; new storefile is " + (sf == null? "none": sf.toString()) + "; store size is " + StringUtils.humanReadableInt(storeSize)); } } @@ -834,16 +837,17 @@ * @param writer output writer * @param filesToCompact which files to compact * @param majorCompaction true to major compact (prune all deletes, max versions, etc) + * @param maxId Readers maximum sequence id. + * @return Product of compaction or null if all cells expired or deleted and + * nothing made it through the compaction. * @throws IOException */ - private void compact(HFile.Writer writer, - List<StoreFile> filesToCompact, - boolean majorCompaction) throws IOException { - // for each file, obtain a scanner: + private HFile.Writer compact(final List<StoreFile> filesToCompact, + final boolean majorCompaction, final long maxId) + throws IOException { + // For each file, obtain a scanner: KeyValueScanner [] scanners = new KeyValueScanner[filesToCompact.size()]; - // init: for (int i = 0; i < filesToCompact.size(); ++i) { - // TODO open a new HFile.Reader w/o block cache. Reader r = filesToCompact.get(i).getReader(); if (r == null) { LOG.warn("StoreFile " + filesToCompact.get(i) + " has a null Reader"); @@ -853,82 +857,101 @@ scanners[i] = new StoreFileScanner(r.getScanner(false)); } + // Make the instantiation lazy in case compaction produces no product; i.e. + // where all source cells are expired or deleted. + HFile.Writer writer = null; + try { if (majorCompaction) { InternalScanner scanner = null; - try { Scan scan = new Scan(); scan.setMaxVersions(family.getMaxVersions()); scanner = new StoreScanner(this, scan, scanners); - // since scanner.next() can return 'false' but still be delivering data, // we have to use a do/while loop. - ArrayList<KeyValue> row = new ArrayList<KeyValue>(); + ArrayList<KeyValue> kvs = new ArrayList<KeyValue>(); boolean more = true; - while ( more ) { - more = scanner.next(row); + while (more) { + more = scanner.next(kvs); // output to writer: - for (KeyValue kv : row) { + for (KeyValue kv : kvs) { + if (writer == null) { + writer = getWriter(this.regionCompactionDir); + } writer.append(kv); } - row.clear(); + kvs.clear(); } } finally { - if (scanner != null) + if (scanner != null) { scanner.close(); + } } } else { MinorCompactingStoreScanner scanner = null; try { scanner = new MinorCompactingStoreScanner(this, scanners); - - while ( scanner.next(writer) ) { } + writer = getWriter(this.regionCompactionDir); + while (scanner.next(writer)) { + // Nothing to do + } } finally { if (scanner != null) scanner.close(); } } - + } finally { + if (writer != null) { + StoreFile.appendMetadata(writer, maxId, majorCompaction); + writer.close(); + } + } + return writer; } /* * It's assumed that the compactLock will be acquired prior to calling this * method! Otherwise, it is not thread-safe! * - * It works by processing a compaction that's been written to disk. + * <p>It works by processing a compaction that's been written to disk. * * <p>It is usually invoked at the end of a compaction, but might also be * invoked at HStore startup, if the prior execution died midway through. * * <p>Moving the compacted TreeMap into place means: * <pre> - * 1) Moving the new compacted MapFile into place - * 2) Unload all replaced MapFiles, close and collect list to delete. + * 1) Moving the new compacted StoreFile into place + * 2) Unload all replaced StoreFile, close and collect list to delete. * 3) Loading the new TreeMap. * 4) Compute new store size * </pre> * * @param compactedFiles list of files that were compacted - * @param compactedFile HStoreFile that is the result of the compaction + * @param compactedFile StoreFile that is the result of the compaction + * @return StoreFile created. May be null. * @throws IOException */ - private void completeCompaction(final List<StoreFile> compactedFiles, + private StoreFile completeCompaction(final List<StoreFile> compactedFiles, final HFile.Writer compactedFile) throws IOException { - // 1. Moving the new files into place. - Path p = null; - try { - p = StoreFile.rename(this.fs, compactedFile.getPath(), - StoreFile.getRandomFilename(fs, this.homedir)); - } catch (IOException e) { - LOG.error("Failed move of compacted file " + compactedFile.getPath(), e); - return; + // 1. Moving the new files into place -- if there is a new file (may not + // be if all cells were expired or deleted). + StoreFile result = null; + if (compactedFile != null) { + Path p = null; + try { + p = StoreFile.rename(this.fs, compactedFile.getPath(), + StoreFile.getRandomFilename(fs, this.homedir)); + } catch (IOException e) { + LOG.error("Failed move of compacted file " + compactedFile.getPath(), e); + return null; + } + result = new StoreFile(this.fs, p, blockcache, this.conf, this.inMemory); } - StoreFile finalCompactedFile = new StoreFile(this.fs, p, blockcache, - this.conf, this.inMemory); this.lock.writeLock().lock(); try { try { + // 2. Unloading // 3. Loading the new TreeMap. // Change this.storefiles so it reflects new state but do not // delete old store files until we have sent out notification of @@ -939,10 +962,12 @@ this.storefiles.remove(e.getKey()); } } - // Add new compacted Reader and store file. - Long orderVal = Long.valueOf(finalCompactedFile.getMaxSequenceId()); - this.storefiles.put(orderVal, finalCompactedFile); - // Tell observers that list of Readers has changed. + // If a StoreFile result, move it into place. May be null. + if (result != null) { + Long orderVal = Long.valueOf(result.getMaxSequenceId()); + this.storefiles.put(orderVal, result); + } + // Tell observers that list of StoreFiles has changed. notifyChangedReadersObservers(); // Finally, delete old store files. for (StoreFile hsf: compactedFiles) { @@ -950,11 +975,10 @@ } } catch (IOException e) { e = RemoteExceptionHandler.checkIOException(e); - LOG.error("Failed replacing compacted files for " + - this.storeNameStr + - ". Compacted file is " + finalCompactedFile.toString() + - ". Files replaced are " + compactedFiles.toString() + - " some of which may have been already removed", e); + LOG.error("Failed replacing compacted files in " + this.storeNameStr + + ". Compacted file is " + (result == null? "none": result.toString()) + + ". Files replaced " + compactedFiles.toString() + + " some of which may have been already removed", e); } // 4. Compute new store size this.storeSize = 0L; @@ -969,6 +993,7 @@ } finally { this.lock.writeLock().unlock(); } + return result; } // //////////////////////////////////////////////////////////////////////////// @@ -1459,8 +1484,12 @@ } } + HRegion getHRegion() { + return this.region; + } + HRegionInfo getHRegionInfo() { - return this.regioninfo; + return this.region.regionInfo; } /** @@ -1595,22 +1624,46 @@ // Setting up the QueryMatcher Get get = new Get(row); - NavigableSet<byte[]> qualifiers = + NavigableSet<byte[]> qualifiers = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR); qualifiers.add(qualifier); QueryMatcher matcher = new QueryMatcher(get, f, qualifiers, this.ttl, keyComparator, 1); - - // Read from memstore - if (this.memstore.get(matcher, result)) { + + boolean newTs = true; + KeyValue kv = null; + // Read from memstore first: + this.memstore.internalGet(this.memstore.kvset, + matcher, result); + if (!result.isEmpty()) { + kv = result.get(0).clone(); + newTs = false; + } else { + // try the snapshot. + this.memstore.internalGet(this.memstore.snapshot, + matcher, result); + if (!result.isEmpty()) { + kv = result.get(0).clone(); + } + } + + if (kv != null) { // Received early-out from memstore // Make a copy of the KV and increment it - KeyValue kv = result.get(0).clone(); byte [] buffer = kv.getBuffer(); int valueOffset = kv.getValueOffset(); value = Bytes.toLong(buffer, valueOffset, Bytes.SIZEOF_LONG) + amount; Bytes.putBytes(buffer, valueOffset, Bytes.toBytes(value), 0, Bytes.SIZEOF_LONG); + if (newTs) { + long currTs = System.currentTimeMillis(); + if (currTs == kv.getTimestamp()) { + currTs++; // just in case something wacky happens. + } + byte [] stampBytes = Bytes.toBytes(currTs); + Bytes.putBytes(buffer, kv.getTimestampOffset(), stampBytes, 0, + Bytes.SIZEOF_LONG); + } return new ICVResult(value, 0, kv); } // Check if we even have storefiles @@ -1663,4 +1716,4 @@ public long heapSize() { return DEEP_OVERHEAD + this.memstore.heapSize(); } -} \ No newline at end of file +}
Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreFileGetScan.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreFileGetScan.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreFileGetScan.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreFileGetScan.java Thu Jul 30 05:35:05 2009 @@ -62,7 +62,7 @@ public void get(List<KeyValue> result) throws IOException { for(HFileScanner scanner : this.scanners) { this.matcher.update(); - if(getStoreFile(scanner, result) || matcher.isDone()) { + if (getStoreFile(scanner, result) || matcher.isDone()) { return; } } @@ -77,11 +77,13 @@ */ public boolean getStoreFile(HFileScanner scanner, List<KeyValue> result) throws IOException { - if(scanner.seekTo(startKey.getBuffer(), startKey.getKeyOffset(), + if (scanner.seekTo(startKey.getBuffer(), startKey.getKeyOffset(), startKey.getKeyLength()) == -1) { // No keys in StoreFile at or after specified startKey // First row may be = our row, so we have to check anyways. byte [] firstKey = scanner.getReader().getFirstKey(); + // Key may be null if storefile is empty. + if (firstKey == null) return false; short rowLen = Bytes.toShort(firstKey, 0, Bytes.SIZEOF_SHORT); int rowOffset = Bytes.SIZEOF_SHORT; if (this.matcher.rowComparator.compareRows(firstKey, rowOffset, rowLen, Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java Thu Jul 30 05:35:05 2009 @@ -162,20 +162,12 @@ continue; case DONE: - if (matcher.filterEntireRow()) { - // nuke all results, and then return. - results.clear(); - } // copy jazz outResult.addAll(results); return true; case DONE_SCAN: - if (matcher.filterEntireRow()) { - // nuke all results, and then return. - results.clear(); - } close(); // copy jazz @@ -202,11 +194,6 @@ throw new RuntimeException("UNEXPECTED"); } } - - if (matcher.filterEntireRow()) { - // nuke all results, and then return. - results.clear(); - } if (!results.isEmpty()) { // copy jazz Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift Thu Jul 30 05:35:05 2009 @@ -74,12 +74,11 @@ 2:i32 maxVersions = 3, 3:string compression = "NONE", 4:bool inMemory = 0, - 5:i32 maxValueLength = 2147483647, - 6:string bloomFilterType = "NONE", - 7:i32 bloomFilterVectorSize = 0, - 8:i32 bloomFilterNbHashes = 0, - 9:bool blockCacheEnabled = 0, - 10:i32 timeToLive = -1 + 5:string bloomFilterType = "NONE", + 6:i32 bloomFilterVectorSize = 0, + 7:i32 bloomFilterNbHashes = 0, + 8:bool blockCacheEnabled = 0, + 9:i32 timeToLive = -1 } /** @@ -463,6 +462,20 @@ 4:list<Text> columns) throws (1:IOError io) + /** + * Open a scanner for a given prefix. That is all rows will have the specified + * prefix. No other rows will be returned. + * + * @param tableName name of table + * @param startAndPrefix the prefix (and thus start row) of the keys you want + * @param columns the columns you want returned + * @return scanner id to use with other scanner calls + */ + ScannerID scannerOpenWithPrefix(1:Text tableName, + 2:Text startAndPrefix, + 3:list<Text> columns) + throws (1:IOError io) + /** * Get a scanner on the current table starting at the specified row and * ending at the last row in the table. Return the specified columns. Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/ThriftServer.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/ThriftServer.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/ThriftServer.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/ThriftServer.java Thu Jul 30 05:35:05 2009 @@ -35,6 +35,9 @@ import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.MasterNotRunningException; +import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.filter.WhileMatchFilter; +import org.apache.hadoop.hbase.filter.PrefixFilter; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; @@ -346,7 +349,11 @@ Get get = new Get(row); for(byte [] column : columnArr) { byte [][] famAndQf = KeyValue.parseColumn(column); - get.addColumn(famAndQf[0], famAndQf[1]); + if (famAndQf[1] == null || famAndQf[1].length == 0) { + get.addFamily(famAndQf[0]); + } else { + get.addColumn(famAndQf[0], famAndQf[1]); + } } get.setTimeRange(Long.MIN_VALUE, timestamp); Result result = table.get(get); @@ -433,18 +440,31 @@ mutateRowTs(tableName, row, mutations, HConstants.LATEST_TIMESTAMP); } - public void mutateRowTs(byte[] tableName, byte[] row, + public void mutateRowTs(byte[] tableName, byte[] row, List<Mutation> mutations, long timestamp) throws IOError, IllegalArgument { HTable table = null; try { table = getTable(tableName); Put put = new Put(row); put.setTimeStamp(timestamp); + + Delete delete = new Delete(row); + for (Mutation m : mutations) { - byte [][] famAndQf = KeyValue.parseColumn(m.column); - put.add(famAndQf[0], famAndQf[1], m.value); + byte[][] famAndQf = KeyValue.parseColumn(m.column); + if (m.isDelete) { + if (famAndQf[1].length == 0) + delete.deleteFamily(famAndQf[0], timestamp); + else + delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp); + } else { + put.add(famAndQf[0], famAndQf[1], m.value); + } } - table.put(put); + if (!delete.isEmpty()) + table.delete(delete); + if (!put.isEmpty()) + table.put(put); } catch (IOException e) { throw new IOError(e.getMessage()); } catch (IllegalArgumentException e) { @@ -456,7 +476,7 @@ throws IOError, IllegalArgument, TException { mutateRowsTs(tableName, rowBatches, HConstants.LATEST_TIMESTAMP); } - + public void mutateRowsTs(byte[] tableName, List<BatchMutation> rowBatches, long timestamp) throws IOError, IllegalArgument, TException { List<Put> puts = new ArrayList<Put>(); @@ -469,9 +489,13 @@ Put put = new Put(row); put.setTimeStamp(timestamp); for (Mutation m : mutations) { - byte [][] famAndQf = KeyValue.parseColumn(m.column); + byte[][] famAndQf = KeyValue.parseColumn(m.column); if (m.isDelete) { - delete.deleteColumns(famAndQf[0], famAndQf[1]); + // no qualifier, family only. + if (famAndQf[1].length == 0) + delete.deleteFamily(famAndQf[0], timestamp); + else + delete.deleteColumns(famAndQf[0], famAndQf[1], timestamp); } else { put.add(famAndQf[0], famAndQf[1], m.value); } @@ -582,7 +606,24 @@ throw new IOError(e.getMessage()); } } - + + @Override + public int scannerOpenWithPrefix(byte[] tableName, byte[] startAndPrefix, List<byte[]> columns) throws IOError, TException { + try { + HTable table = getTable(tableName); + byte [][] columnsArray = null; + columnsArray = columns.toArray(new byte[0][]); + Scan scan = new Scan(startAndPrefix); + scan.addColumns(columnsArray); + Filter f = new WhileMatchFilter( + new PrefixFilter(startAndPrefix)); + scan.setFilter(f); + return addScanner(table.getScanner(scan)); + } catch (IOException e) { + throw new IOError(e.getMessage()); + } + } + public int scannerOpenTs(byte[] tableName, byte[] startRow, List<byte[]> columns, long timestamp) throws IOError, TException { try { Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java Thu Jul 30 05:35:05 2009 @@ -1,4 +1,6 @@ -/** +/* + * Copyright 2009 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 @@ -15,11 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Autogenerated by Thrift - * - * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - */ + package org.apache.hadoop.hbase.thrift.generated; import java.util.List; Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java Thu Jul 30 05:35:05 2009 @@ -1,4 +1,6 @@ -/** +/* + * Copyright 2009 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 @@ -15,11 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Autogenerated by Thrift - * - * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - */ package org.apache.hadoop.hbase.thrift.generated; import java.util.List; Modified: hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java?rev=799173&r1=799172&r2=799173&view=diff ============================================================================== --- hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java (original) +++ hadoop/hbase/trunk_on_hadoop-0.18.3/src/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java Thu Jul 30 05:35:05 2009 @@ -1,4 +1,6 @@ -/** +/* + * Copyright 2009 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 @@ -15,11 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Autogenerated by Thrift - * - * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - */ package org.apache.hadoop.hbase.thrift.generated; import java.util.List; @@ -129,7 +126,6 @@ int maxVersions, String compression, boolean inMemory, - int maxValueLength, String bloomFilterType, int bloomFilterVectorSize, int bloomFilterNbHashes,
