Exemplo n.º 1
0
 @Override
 public int compare(final KeyValue left, final KeyValue right) {
   return rawcomparator.compare(
       left.getBuffer(),
       left.getOffset() + KeyValue.ROW_OFFSET,
       left.getKeyLength(),
       right.getBuffer(),
       right.getOffset() + KeyValue.ROW_OFFSET,
       right.getKeyLength());
 }
Exemplo n.º 2
0
 /**
  * Add key/value to file. Keys must be added in an order that agrees with the Comparator passed on
  * construction.
  *
  * @param kv KeyValue to add. Cannot be empty nor null.
  * @throws IOException
  */
 @Override
 public void append(final KeyValue kv) throws IOException {
   append(
       kv.getMemstoreTS(),
       kv.getBuffer(),
       kv.getKeyOffset(),
       kv.getKeyLength(),
       kv.getBuffer(),
       kv.getValueOffset(),
       kv.getValueLength());
   this.maxMemstoreTS = Math.max(this.maxMemstoreTS, kv.getMemstoreTS());
 }
Exemplo n.º 3
0
  /**
   * Add key/value to file. Keys must be added in an order that agrees with the Comparator passed on
   * construction.
   *
   * @param kv KeyValue to add. Cannot be empty nor null.
   * @throws IOException
   */
  @Override
  public void append(final KeyValue kv) throws IOException {
    byte[] key = kv.getBuffer();
    int koffset = kv.getKeyOffset();
    int klength = kv.getKeyLength();
    byte[] value = kv.getValueArray();
    int voffset = kv.getValueOffset();
    int vlength = kv.getValueLength();
    boolean dupKey = checkKey(key, koffset, klength);
    checkValue(value, voffset, vlength);
    if (!dupKey) {
      checkBlockBoundary();
    }

    if (!fsBlockWriter.isWriting()) newBlock();

    fsBlockWriter.write(kv);

    totalKeyLength += klength;
    totalValueLength += vlength;

    // Are we the first key in this block?
    if (firstKeyInBlock == null) {
      // Copy the key.
      firstKeyInBlock = new byte[klength];
      System.arraycopy(key, koffset, firstKeyInBlock, 0, klength);
    }

    lastKeyBuffer = key;
    lastKeyOffset = koffset;
    lastKeyLength = klength;
    entryCount++;
    this.maxMemstoreTS = Math.max(this.maxMemstoreTS, kv.getMvccVersion());
  }
Exemplo n.º 4
0
 @SuppressWarnings("deprecation")
 @Override
 protected void writeToBuffer(MappedByteBuffer buffer, Tuple e) {
   KeyValue kv = KeyValueUtil.ensureKeyValue(e.getValue(0));
   buffer.putInt(kv.getLength() + Bytes.SIZEOF_INT);
   buffer.putInt(kv.getLength());
   buffer.put(kv.getBuffer(), kv.getOffset(), kv.getLength());
 }
Exemplo n.º 5
0
    @Override
    public void examine(SkipScanFilter skipper) {
      KeyValue kv = KeyValue.createFirstOnRow(rowkey);
      skipper.reset();
      assertFalse(skipper.filterAllRemaining());
      assertFalse(skipper.filterRowKey(kv.getBuffer(), kv.getRowOffset(), kv.getRowLength()));

      assertEquals(kv.toString(), ReturnCode.INCLUDE, skipper.filterKeyValue(kv));
    }
Exemplo n.º 6
0
    @Override
    public void examine(SkipScanFilter skipper) {
      KeyValue kv = KeyValue.createFirstOnRow(rowkey);
      skipper.reset();
      assertFalse(skipper.filterAllRemaining());
      assertFalse(skipper.filterRowKey(kv.getBuffer(), kv.getRowOffset(), kv.getRowLength()));

      assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, skipper.filterKeyValue(kv));
      assertEquals(KeyValue.createFirstOnRow(hint), skipper.getNextKeyHint(kv));
    }
Exemplo n.º 7
0
 static boolean reseekAtOrAfter(HFileScanner s, KeyValue k) throws IOException {
   // This function is similar to seekAtOrAfter function
   int result = s.reseekTo(k.getBuffer(), k.getKeyOffset(), k.getKeyLength());
   if (result <= 0) {
     return true;
   } else {
     // passed KV is larger than current KV in file, if there is a next
     // it is after, if not then this scanner is done.
     return s.next();
   }
 }
Exemplo n.º 8
0
  @Test
  public void testNextOnSample() throws IOException {
    List<KeyValue> sampleKv = generator.generateTestKeyValues(NUMBER_OF_KV, includesTags);

    for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
      // Off heap block data support not added for PREFIX_TREE DBE yet.
      // TODO remove this once support is added. HBASE-12298
      if (this.useOffheapData && encoding == DataBlockEncoding.PREFIX_TREE) continue;
      if (encoding.getEncoder() == null) {
        continue;
      }
      DataBlockEncoder encoder = encoding.getEncoder();
      ByteBuffer encodedBuffer =
          encodeKeyValues(
              encoding,
              sampleKv,
              getEncodingContext(Compression.Algorithm.NONE, encoding),
              this.useOffheapData);
      HFileContext meta =
          new HFileContextBuilder()
              .withHBaseCheckSum(false)
              .withIncludesMvcc(includesMemstoreTS)
              .withIncludesTags(includesTags)
              .withCompression(Compression.Algorithm.NONE)
              .build();
      DataBlockEncoder.EncodedSeeker seeker =
          encoder.createSeeker(
              CellComparator.COMPARATOR, encoder.newDataBlockDecodingContext(meta));
      seeker.setCurrentBuffer(new SingleByteBuff(encodedBuffer));
      int i = 0;
      do {
        KeyValue expectedKeyValue = sampleKv.get(i);
        Cell cell = seeker.getCell();
        if (CellComparator.COMPARATOR.compareKeyIgnoresMvcc(expectedKeyValue, cell) != 0) {
          int commonPrefix =
              CellUtil.findCommonPrefixInFlatKey(expectedKeyValue, cell, false, true);
          fail(
              String.format(
                  "next() produces wrong results "
                      + "encoder: %s i: %d commonPrefix: %d"
                      + "\n expected %s\n actual      %s",
                  encoder.toString(),
                  i,
                  commonPrefix,
                  Bytes.toStringBinary(
                      expectedKeyValue.getBuffer(),
                      expectedKeyValue.getKeyOffset(),
                      expectedKeyValue.getKeyLength()),
                  CellUtil.toString(cell, false)));
        }
        i++;
      } while (seeker.next());
    }
  }
  /**
   * Check if the specified KeyValue buffer has been deleted by a previously seen delete.
   *
   * @param kv
   * @param ds
   * @return True is the specified KeyValue is deleted, false if not
   */
  public boolean isDeleted(final KeyValue kv, final NavigableSet<KeyValue> ds) {
    if (deletes == null || deletes.isEmpty()) return false;
    for (KeyValue d : ds) {
      long kvts = kv.getTimestamp();
      long dts = d.getTimestamp();
      if (d.isDeleteFamily()) {
        if (kvts <= dts) return true;
        continue;
      }
      // Check column
      int ret =
          Bytes.compareTo(
              kv.getBuffer(),
              kv.getQualifierOffset(),
              kv.getQualifierLength(),
              d.getBuffer(),
              d.getQualifierOffset(),
              d.getQualifierLength());
      if (ret <= -1) {
        // This delete is for an earlier column.
        continue;
      } else if (ret >= 1) {
        // Beyond this kv.
        break;
      }
      // Check Timestamp
      if (kvts > dts) return false;

      // Check Type
      switch (KeyValue.Type.codeToType(d.getType())) {
        case Delete:
          return kvts == dts;
        case DeleteColumn:
          return true;
        default:
          continue;
      }
    }
    return false;
  }
 boolean isTargetTable(final KeyValue kv) {
   if (!metaregion) return true;
   // Compare start of keys row.  Compare including delimiter.  Saves having
   // to calculate where tablename ends in the candidate kv.
   return Bytes.compareTo(
           this.targetkey.getBuffer(),
           this.rowoffset,
           this.tablenamePlusDelimiterLength,
           kv.getBuffer(),
           kv.getRowOffset(),
           this.tablenamePlusDelimiterLength)
       == 0;
 }
Exemplo n.º 11
0
  /**
   * Binary search for latest column value without allocating memory in the process
   *
   * @param r
   * @param searchTerm
   * @return
   */
  public static KeyValue getColumnLatest(List<KeyValue> kvs, KeyValue searchTerm) {
    if (kvs.size() == 0) {
      return null;
    }

    // pos === ( -(insertion point) - 1)
    int pos = Collections.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
    // never will exact match
    if (pos < 0) {
      pos = (pos + 1) * -1;
      // pos is now insertion point
    }
    if (pos == kvs.size()) {
      return null; // doesn't exist
    }

    KeyValue kv = kvs.get(pos);
    if (Bytes.compareTo(
            kv.getBuffer(),
            kv.getFamilyOffset(),
            kv.getFamilyLength(),
            searchTerm.getBuffer(),
            searchTerm.getFamilyOffset(),
            searchTerm.getFamilyLength())
        != 0) {
      return null;
    }
    if (Bytes.compareTo(
            kv.getBuffer(),
            kv.getQualifierOffset(),
            kv.getQualifierLength(),
            searchTerm.getBuffer(),
            searchTerm.getQualifierOffset(),
            searchTerm.getQualifierLength())
        != 0) {
      return null;
    }
    return kv;
  }
Exemplo n.º 12
0
 /**
  * @param s
  * @param k
  * @return
  * @throws IOException
  */
 public static boolean seekAtOrAfter(HFileScanner s, KeyValue k) throws IOException {
   int result = s.seekTo(k.getBuffer(), k.getKeyOffset(), k.getKeyLength());
   if (result < 0) {
     // Passed KV is smaller than first KV in file, work from start of file
     return s.seekTo();
   } else if (result > 0) {
     // Passed KV is larger than current KV in file, if there is a next
     // it is the "after", if not then this scanner is done.
     return s.next();
   }
   // Seeked to the exact key
   return true;
 }
Exemplo n.º 13
0
 /** Binary search for latest column value without allocating memory in the process */
 public static KeyValue getColumnLatest(List<KeyValue> kvs, byte[] family, byte[] qualifier) {
   KeyValue kv = kvs.get(0);
   return KeyValueUtil.getColumnLatest(
       kvs,
       kv.getBuffer(),
       kv.getRowOffset(),
       kv.getRowLength(),
       family,
       0,
       family.length,
       qualifier,
       0,
       qualifier.length);
 }
Exemplo n.º 14
0
  /**
   * Convert list of KeyValues to byte buffer.
   *
   * @param keyValues list of KeyValues to be converted.
   * @return buffer with content from key values
   */
  public static ByteBuffer convertKvToByteBuffer(
      List<KeyValue> keyValues, boolean includesMemstoreTS) {
    int totalSize = 0;
    for (KeyValue kv : keyValues) {
      totalSize += kv.getLength();
      if (includesMemstoreTS) {
        totalSize += WritableUtils.getVIntSize(kv.getMvccVersion());
      }
    }

    ByteBuffer result = ByteBuffer.allocate(totalSize);
    for (KeyValue kv : keyValues) {
      result.put(kv.getBuffer(), kv.getOffset(), kv.getLength());
      if (includesMemstoreTS) {
        ByteBufferUtils.writeVLong(result, kv.getMvccVersion());
      }
    }
    return result;
  }
 /**
  * @param c
  * @param kv Presume first on row: i.e. empty column, maximum timestamp and a type of Type.Maximum
  * @param ttl Time to live in ms for this Store
  * @param metaregion True if this is .META. or -ROOT- region.
  */
 GetClosestRowBeforeTracker(
     final KVComparator c, final KeyValue kv, final long ttl, final boolean metaregion) {
   super();
   this.metaregion = metaregion;
   this.targetkey = kv;
   // If we are in a metaregion, then our table name is the prefix on the
   // targetkey.
   this.rowoffset = kv.getRowOffset();
   int l = -1;
   if (metaregion) {
     l =
         KeyValue.getDelimiter(kv.getBuffer(), rowoffset, kv.getRowLength(), HConstants.DELIMITER)
             - this.rowoffset;
   }
   this.tablenamePlusDelimiterLength = metaregion ? l + 1 : -1;
   this.oldestts = System.currentTimeMillis() - ttl;
   this.kvcomparator = c;
   KeyValue.RowComparator rc = new KeyValue.RowComparator(this.kvcomparator);
   this.deletes = new TreeMap<KeyValue, NavigableSet<KeyValue>>(rc);
 }
 @Override
 public MetaDataMutationResult updateIndexState(
     List<Mutation> tableMetadata, String parentTableName) throws SQLException {
   byte[][] rowKeyMetadata = new byte[3][];
   SchemaUtil.getVarChars(tableMetadata.get(0).getRow(), rowKeyMetadata);
   KeyValue newKV = tableMetadata.get(0).getFamilyMap().get(TABLE_FAMILY_BYTES).get(0);
   PIndexState newState =
       PIndexState.fromSerializedValue(newKV.getBuffer()[newKV.getValueOffset()]);
   String schemaName = Bytes.toString(rowKeyMetadata[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX]);
   String indexName = Bytes.toString(rowKeyMetadata[PhoenixDatabaseMetaData.TABLE_NAME_INDEX]);
   String indexTableName = SchemaUtil.getTableName(schemaName, indexName);
   PTable index = metaData.getTable(indexTableName);
   index =
       PTableImpl.makePTable(
           index,
           newState == PIndexState.USABLE
               ? PIndexState.ACTIVE
               : newState == PIndexState.UNUSABLE ? PIndexState.INACTIVE : newState);
   return new MetaDataMutationResult(MutationCode.TABLE_ALREADY_EXISTS, 0, index);
 }
Exemplo n.º 17
0
  /**
   * Write out a split reference. Package local so it doesnt leak out of regionserver.
   *
   * @param hri {@link HRegionInfo} of the destination
   * @param familyName Column Family Name
   * @param f File to split.
   * @param splitRow Split Row
   * @param top True if we are referring to the top half of the hfile.
   * @return Path to created reference.
   * @throws IOException
   */
  Path splitStoreFile(
      final HRegionInfo hri,
      final String familyName,
      final StoreFile f,
      final byte[] splitRow,
      final boolean top)
      throws IOException {

    // Check whether the split row lies in the range of the store file
    // If it is outside the range, return directly.
    if (!isIndexTable()) {
      if (top) {
        // check if larger than last key.
        KeyValue splitKey = KeyValue.createFirstOnRow(splitRow);
        byte[] lastKey = f.createReader().getLastKey();
        // If lastKey is null means storefile is empty.
        if (lastKey == null) return null;
        if (f.getReader()
                .getComparator()
                .compareFlatKey(
                    splitKey.getBuffer(),
                    splitKey.getKeyOffset(),
                    splitKey.getKeyLength(),
                    lastKey,
                    0,
                    lastKey.length)
            > 0) {
          return null;
        }
      } else {
        // check if smaller than first key
        KeyValue splitKey = KeyValue.createLastOnRow(splitRow);
        byte[] firstKey = f.createReader().getFirstKey();
        // If firstKey is null means storefile is empty.
        if (firstKey == null) return null;
        if (f.getReader()
                .getComparator()
                .compareFlatKey(
                    splitKey.getBuffer(),
                    splitKey.getKeyOffset(),
                    splitKey.getKeyLength(),
                    firstKey,
                    0,
                    firstKey.length)
            < 0) {
          return null;
        }
      }

      f.getReader().close(true);
    }

    Path splitDir = new Path(getSplitsDir(hri), familyName);
    // A reference to the bottom half of the hsf store file.
    Reference r =
        top ? Reference.createTopReference(splitRow) : Reference.createBottomReference(splitRow);
    // Add the referred-to regions name as a dot separated suffix.
    // See REF_NAME_REGEX regex above.  The referred-to regions name is
    // up in the path of the passed in <code>f</code> -- parentdir is family,
    // then the directory above is the region name.
    String parentRegionName = regionInfo.getEncodedName();
    // Write reference with same file id only with the other region name as
    // suffix and into the new region location (under same family).
    Path p = new Path(splitDir, f.getPath().getName() + "." + parentRegionName);
    return r.write(fs, p);
  }
Exemplo n.º 18
0
  /**
   * Override the preAppend for checkAndPut and checkAndDelete, as we need the ability to a) set the
   * TimeRange for the Get being done and b) return something back to the client to indicate
   * success/failure
   */
  @SuppressWarnings("deprecation")
  @Override
  public Result preAppend(
      final ObserverContext<RegionCoprocessorEnvironment> e, final Append append)
      throws IOException {
    byte[] opBuf = append.getAttribute(OPERATION_ATTRIB);
    if (opBuf == null) {
      return null;
    }
    Op op = Op.values()[opBuf[0]];

    long clientTimestamp = HConstants.LATEST_TIMESTAMP;
    byte[] clientTimestampBuf = append.getAttribute(MAX_TIMERANGE_ATTRIB);
    if (clientTimestampBuf != null) {
      clientTimestamp = Bytes.toLong(clientTimestampBuf);
    }
    boolean hadClientTimestamp = (clientTimestamp != HConstants.LATEST_TIMESTAMP);
    if (hadClientTimestamp) {
      // Prevent race condition of creating two sequences at the same timestamp
      // by looking for a sequence at or after the timestamp at which it'll be
      // created.
      if (op == Op.CREATE_SEQUENCE) {
        clientTimestamp++;
      }
    } else {
      clientTimestamp = EnvironmentEdgeManager.currentTimeMillis();
      clientTimestampBuf = Bytes.toBytes(clientTimestamp);
    }

    RegionCoprocessorEnvironment env = e.getEnvironment();
    // We need to set this to prevent region.append from being called
    e.bypass();
    e.complete();
    HRegion region = env.getRegion();
    byte[] row = append.getRow();
    region.startRegionOperation();
    try {
      Integer lid = region.getLock(null, row, true);
      try {
        KeyValue keyValue = append.getFamilyMap().values().iterator().next().iterator().next();
        byte[] family = keyValue.getFamily();
        byte[] qualifier = keyValue.getQualifier();

        Get get = new Get(row);
        get.setTimeRange(MetaDataProtocol.MIN_TABLE_TIMESTAMP, clientTimestamp);
        get.addColumn(family, qualifier);
        Result result = region.get(get);
        if (result.isEmpty()) {
          if (op == Op.DROP_SEQUENCE || op == Op.RESET_SEQUENCE) {
            return getErrorResult(
                row, clientTimestamp, SQLExceptionCode.SEQUENCE_UNDEFINED.getErrorCode());
          }
        } else {
          if (op == Op.CREATE_SEQUENCE) {
            return getErrorResult(
                row, clientTimestamp, SQLExceptionCode.SEQUENCE_ALREADY_EXIST.getErrorCode());
          }
        }
        Mutation m = null;
        switch (op) {
          case RESET_SEQUENCE:
            KeyValue currentValueKV = result.raw()[0];
            long expectedValue =
                PDataType.LONG
                    .getCodec()
                    .decodeLong(append.getAttribute(CURRENT_VALUE_ATTRIB), 0, null);
            long value =
                PDataType.LONG
                    .getCodec()
                    .decodeLong(currentValueKV.getBuffer(), currentValueKV.getValueOffset(), null);
            // Timestamp should match exactly, or we may have the wrong sequence
            if (expectedValue != value || currentValueKV.getTimestamp() != clientTimestamp) {
              return new Result(
                  Collections.singletonList(
                      KeyValueUtil.newKeyValue(
                          row,
                          PhoenixDatabaseMetaData.SEQUENCE_FAMILY_BYTES,
                          QueryConstants.EMPTY_COLUMN_BYTES,
                          currentValueKV.getTimestamp(),
                          ByteUtil.EMPTY_BYTE_ARRAY)));
            }
            m = new Put(row, currentValueKV.getTimestamp());
            m.getFamilyMap().putAll(append.getFamilyMap());
            break;
          case DROP_SEQUENCE:
            m = new Delete(row, clientTimestamp, null);
            break;
          case CREATE_SEQUENCE:
            m = new Put(row, clientTimestamp);
            m.getFamilyMap().putAll(append.getFamilyMap());
            break;
        }
        if (!hadClientTimestamp) {
          for (List<KeyValue> kvs : m.getFamilyMap().values()) {
            for (KeyValue kv : kvs) {
              kv.updateLatestStamp(clientTimestampBuf);
            }
          }
        }
        @SuppressWarnings("unchecked")
        Pair<Mutation, Integer>[] mutations = new Pair[1];
        mutations[0] = new Pair<Mutation, Integer>(m, lid);
        region.batchMutate(mutations);
        long serverTimestamp = MetaDataUtil.getClientTimeStamp(m);
        // Return result with single KeyValue. The only piece of information
        // the client cares about is the timestamp, which is the timestamp of
        // when the mutation was actually performed (useful in the case of .
        return new Result(
            Collections.singletonList(
                KeyValueUtil.newKeyValue(
                    row,
                    PhoenixDatabaseMetaData.SEQUENCE_FAMILY_BYTES,
                    QueryConstants.EMPTY_COLUMN_BYTES,
                    serverTimestamp,
                    SUCCESS_VALUE)));
      } finally {
        region.releaseRowLock(lid);
      }
    } catch (Throwable t) {
      ServerUtil.throwIOException("Increment of sequence " + Bytes.toStringBinary(row), t);
      return null; // Impossible
    } finally {
      region.closeRegionOperation();
    }
  }
 @Override
 public ReturnCode filterKeyValue(KeyValue kv) {
   return navigate(kv.getBuffer(), kv.getRowOffset(), kv.getRowLength(), Terminate.AFTER);
 }
Exemplo n.º 20
0
 /**
  * Use PreIncrement hook of BaseRegionObserver to overcome deficiencies in Increment
  * implementation (HBASE-10254): 1) Lack of recognition and identification of when the key value
  * to increment doesn't exist 2) Lack of the ability to set the timestamp of the updated key
  * value. Works the same as existing region.increment(), except assumes there is a single column
  * to increment and uses Phoenix LONG encoding.
  *
  * @author jtaylor
  * @since 3.0.0
  */
 @Override
 public Result preIncrement(
     final ObserverContext<RegionCoprocessorEnvironment> e, final Increment increment)
     throws IOException {
   RegionCoprocessorEnvironment env = e.getEnvironment();
   // We need to set this to prevent region.increment from being called
   e.bypass();
   e.complete();
   HRegion region = env.getRegion();
   byte[] row = increment.getRow();
   TimeRange tr = increment.getTimeRange();
   region.startRegionOperation();
   try {
     Integer lid = region.getLock(null, row, true);
     try {
       long maxTimestamp = tr.getMax();
       if (maxTimestamp == HConstants.LATEST_TIMESTAMP) {
         maxTimestamp = EnvironmentEdgeManager.currentTimeMillis();
         tr = new TimeRange(tr.getMin(), maxTimestamp);
       }
       Get get = new Get(row);
       get.setTimeRange(tr.getMin(), tr.getMax());
       for (Map.Entry<byte[], NavigableMap<byte[], Long>> entry :
           increment.getFamilyMap().entrySet()) {
         byte[] cf = entry.getKey();
         for (byte[] cq : entry.getValue().keySet()) {
           get.addColumn(cf, cq);
         }
       }
       Result result = region.get(get);
       if (result.isEmpty()) {
         return getErrorResult(
             row, maxTimestamp, SQLExceptionCode.SEQUENCE_UNDEFINED.getErrorCode());
       }
       KeyValue currentValueKV = Sequence.getCurrentValueKV(result);
       KeyValue incrementByKV = Sequence.getIncrementByKV(result);
       KeyValue cacheSizeKV = Sequence.getCacheSizeKV(result);
       long value =
           PDataType.LONG
               .getCodec()
               .decodeLong(currentValueKV.getBuffer(), currentValueKV.getValueOffset(), null);
       long incrementBy =
           PDataType.LONG
               .getCodec()
               .decodeLong(incrementByKV.getBuffer(), incrementByKV.getValueOffset(), null);
       int cacheSize =
           PDataType.INTEGER
               .getCodec()
               .decodeInt(cacheSizeKV.getBuffer(), cacheSizeKV.getValueOffset(), null);
       value += incrementBy * cacheSize;
       byte[] valueBuffer = new byte[PDataType.LONG.getByteSize()];
       PDataType.LONG.getCodec().encodeLong(value, valueBuffer, 0);
       Put put = new Put(row, currentValueKV.getTimestamp());
       // Hold timestamp constant for sequences, so that clients always only see the latest value
       // regardless of when they connect.
       KeyValue newCurrentValueKV =
           KeyValueUtil.newKeyValue(
               row,
               currentValueKV.getFamily(),
               currentValueKV.getQualifier(),
               currentValueKV.getTimestamp(),
               valueBuffer);
       put.add(newCurrentValueKV);
       @SuppressWarnings("unchecked")
       Pair<Mutation, Integer>[] mutations = new Pair[1];
       mutations[0] = new Pair<Mutation, Integer>(put, lid);
       region.batchMutate(mutations);
       return Sequence.replaceCurrentValueKV(result, newCurrentValueKV);
     } finally {
       region.releaseRowLock(lid);
     }
   } catch (Throwable t) {
     ServerUtil.throwIOException("Increment of sequence " + Bytes.toStringBinary(row), t);
     return null; // Impossible
   } finally {
     region.closeRegionOperation();
   }
 }
Exemplo n.º 21
0
  /**
   * Pretend we have done a seek but don't do it yet, if possible. The hope is that we find
   * requested columns in more recent files and won't have to seek in older files. Creates a fake
   * key/value with the given row/column and the highest (most recent) possible timestamp we might
   * get from this file. When users of such "lazy scanner" need to know the next KV precisely (e.g.
   * when this scanner is at the top of the heap), they run {@link #enforceSeek()}.
   *
   * <p>Note that this function does guarantee that the current KV of this scanner will be advanced
   * to at least the given KV. Because of this, it does have to do a real seek in cases when the
   * seek timestamp is older than the highest timestamp of the file, e.g. when we are trying to seek
   * to the next row/column and use OLDEST_TIMESTAMP in the seek key.
   */
  @Override
  public boolean requestSeek(KeyValue kv, boolean forward, boolean useBloom) throws IOException {
    if (kv.getFamilyLength() == 0) {
      useBloom = false;
    }

    boolean haveToSeek = true;
    if (useBloom) {
      // check ROWCOL Bloom filter first.
      if (reader.getBloomFilterType() == StoreFile.BloomType.ROWCOL) {
        haveToSeek =
            reader.passesGeneralBloomFilter(
                kv.getBuffer(),
                kv.getRowOffset(),
                kv.getRowLength(),
                kv.getBuffer(),
                kv.getQualifierOffset(),
                kv.getQualifierLength());
      } else if (this.matcher != null && !matcher.hasNullColumnInQuery() && kv.isDeleteFamily()) {
        // if there is no such delete family kv in the store file,
        // then no need to seek.
        haveToSeek =
            reader.passesDeleteFamilyBloomFilter(
                kv.getBuffer(), kv.getRowOffset(), kv.getRowLength());
      }
    }

    delayedReseek = forward;
    delayedSeekKV = kv;

    if (haveToSeek) {
      // This row/column might be in this store file (or we did not use the
      // Bloom filter), so we still need to seek.
      realSeekDone = false;
      long maxTimestampInFile = reader.getMaxTimestamp();
      long seekTimestamp = kv.getTimestamp();
      if (seekTimestamp > maxTimestampInFile) {
        // Create a fake key that is not greater than the real next key.
        // (Lower timestamps correspond to higher KVs.)
        // To understand this better, consider that we are asked to seek to
        // a higher timestamp than the max timestamp in this file. We know that
        // the next point when we have to consider this file again is when we
        // pass the max timestamp of this file (with the same row/column).
        cur = kv.createFirstOnRowColTS(maxTimestampInFile);
      } else {
        // This will be the case e.g. when we need to seek to the next
        // row/column, and we don't know exactly what they are, so we set the
        // seek key's timestamp to OLDEST_TIMESTAMP to skip the rest of this
        // row/column.
        enforceSeek();
      }
      return cur != null;
    }

    // Multi-column Bloom filter optimization.
    // Create a fake key/value, so that this scanner only bubbles up to the top
    // of the KeyValueHeap in StoreScanner after we scanned this row/column in
    // all other store files. The query matcher will then just skip this fake
    // key/value and the store scanner will progress to the next column. This
    // is obviously not a "real real" seek, but unlike the fake KV earlier in
    // this method, we want this to be propagated to ScanQueryMatcher.
    cur = kv.createLastOnRowCol();

    realSeekDone = true;
    return true;
  }