Esempio n. 1
0
  @Test
  public void stringSerialization() {
    // Characters
    DataOutput out = serialize.getDataOutput(((int) Character.MAX_VALUE) * 2 + 8, true);
    for (char c = Character.MIN_VALUE; c < Character.MAX_VALUE; c++) {
      out.writeObjectNotNull(Character.valueOf(c));
    }
    ReadBuffer b = out.getStaticBuffer().asReadBuffer();
    for (char c = Character.MIN_VALUE; c < Character.MAX_VALUE; c++) {
      assertEquals(c, serialize.readObjectNotNull(b, Character.class).charValue());
    }

    // String
    for (int t = 0; t < 10000; t++) {
      DataOutput out1 = serialize.getDataOutput(32 + 5, true);
      DataOutput out2 = serialize.getDataOutput(32 + 5, true);
      String s1 = RandomGenerator.randomString(1, 32);
      String s2 = RandomGenerator.randomString(1, 32);
      out1.writeObjectNotNull(s1);
      out2.writeObjectNotNull(s2);
      StaticBuffer b1 = out1.getStaticBuffer();
      StaticBuffer b2 = out2.getStaticBuffer();
      assertEquals(s1, serialize.readObjectNotNull(b1.asReadBuffer(), String.class));
      assertEquals(s2, serialize.readObjectNotNull(b2.asReadBuffer(), String.class));
      assertEquals(
          s1 + " vs " + s2, Integer.signum(s1.compareTo(s2)), Integer.signum(b1.compareTo(b2)));
    }
  }
  /**
   * This class relies heavily on the behavior of segmented scans with respect to which hash keys
   * are scanned by each segment. Here's a rough ASCII example to help illustrate:
   * ___________________________ |hk:A |hk:B | ---------------------------- ^segment 1 ^segment 2
   *
   * <p>Because we are scanning in segments across the entire hash key space, it is possible for the
   * same hash key to appear in two different segments. We are also running all of the scan segments
   * in parallel, so we have no control over which segment returns first.
   *
   * <p>In the example, if segment 2 was the first segment to post a result, we would store hk:B as
   * a "boundary" key. That way when segment 1 eventually reaches hk:B in its scan, we know that
   * another segment has already returned this hash key and we can safely skip returning it.
   *
   * <p>By doing this, we avoid returning a RecordIterator for the same hash key twice and we only
   * need to store at most 2 hash keys per segment.
   */
  @Override
  public List<SingleKeyRecordIterator> buildRecordIterators(ScanContext scanContext) {
    final ScanResult dynamoDbResult = scanContext.getScanResult();
    final int segment = scanContext.getScanRequest().getSegment();
    final List<Map<String, AttributeValue>> items = dynamoDbResult.getItems();
    // If the scan returned no results, we need to shortcut and just throw back an empty result set
    if (items.isEmpty()) {
      return Collections.emptyList();
    }

    List<SingleKeyRecordIterator> recordIterators = Lists.newLinkedList();

    final Iterator<Map<String, AttributeValue>> itemIterator = items.iterator();
    final Map<String, AttributeValue> firstItem = itemIterator.next();
    final StaticBuffer firstKey = new KeyBuilder(firstItem).build(Constants.TITAN_HASH_KEY);

    // Computes the full set of boundary keys up to this point. This includes the previous end key
    // for this segment.
    final ImmutableSet<StaticBuffer> boundaryKeys = aggregateBoundaryKeys();

    // The first key in this scan segment might already have been returned by a previous scan
    // segment
    if (!boundaryKeys.contains(firstKey)) {
      recordIterators.add(buildRecordIteratorForHashKey(firstKey));
    }

    StaticBuffer hashKey = firstKey;
    while (itemIterator.hasNext()) {
      final Optional<StaticBuffer> nextKey = findNextHashKey(itemIterator, hashKey);
      if (nextKey.isPresent()) {
        // Found a new hash key. Make a record iterator and look for the next unique hash key
        hashKey = nextKey.get();
        recordIterators.add(buildRecordIteratorForHashKey(hashKey));
      }
    }

    // If we've already seen the final hashKey in a previous scan segment result, we want to avoid
    // returning it again.
    if (!hashKey.equals(firstKey) && boundaryKeys.contains(hashKey)) {
      recordIterators.remove(recordIterators.size() - 1);
    }

    // Update the boundary keys for this segment
    if (scanContext.isFirstResult()) {
      setInitialBoundaryKeys(segment, firstKey, hashKey);
    } else {
      updateLastKey(segment, hashKey);
    }
    return recordIterators;
  }
  private Optional<StaticBuffer> findNextHashKey(
      Iterator<Map<String, AttributeValue>> itemIterator, StaticBuffer previousKey) {
    Optional<StaticBuffer> result = Optional.absent();

    while (itemIterator.hasNext() && !result.isPresent()) {
      final StaticBuffer nextKey =
          new KeyBuilder(itemIterator.next()).build(Constants.TITAN_HASH_KEY);
      if (!nextKey.equals(previousKey)) {
        result = Optional.of(nextKey);
      }
    }

    return result;
  }
Esempio n. 4
0
 @Override
 public boolean equals(Object other) {
   if (this == other) return true;
   else if (other == null) return false;
   else if (!getClass().isInstance(other)) return false;
   KeySliceQuery oth = (KeySliceQuery) other;
   return key.equals(oth.key) && super.equals(oth);
 }
Esempio n. 5
0
 @Override
 public int hashCode() {
   if (hashcode == 0) {
     hashcode = key.hashCode() * 102329 + super.hashCode();
     if (hashcode == 0) hashcode = 1;
   }
   return hashcode;
 }
Esempio n. 6
0
 public boolean subsumes(KeySliceQuery oth) {
   return key.equals(oth.key) && super.subsumes(oth);
 }