writeNumber(orderedCode, part, (long) ((Boolean) value ? 0 : 1)); } else if (value instanceof Long) { writeNumber(orderedCode, part, (long) value); } else if (value instanceof Double) { writeNumber(orderedCode, part, Double.doubleToLongBits((double) value)); } else if (value instanceof String) { writeString(orderedCode, part, (String) value); } else if (value instanceof ByteArray) { writeBytes(orderedCode, part, (ByteArray) value); } else if (value instanceof Timestamp) { writeTimestamp(orderedCode, part, (Timestamp) value); } else if (value instanceof Date) { writeNumber(orderedCode, part, encodeDate((Date) value)); } else { throw new IllegalArgumentException("Unknown key part " + value);
private void verifyEncodedOrdering(SpannerSchema schema, List<Mutation> expectedMutations) { MutationKeyEncoder encoder = new MutationKeyEncoder(schema); Assert.assertEquals(5, expectedMutations.size()); // mix them up. List<Mutation> unsortedMutations = Arrays.asList( expectedMutations.get(3), expectedMutations.get(4), expectedMutations.get(1), expectedMutations.get(2), expectedMutations.get(0)); // use a Map to re-sort them by the encoded key order, // This allows the original values to be reported on error, Map<byte[], Mutation> mutationsByEncoding = new TreeMap<>(UnsignedBytes.lexicographicalComparator()); for (Mutation m : unsortedMutations) { mutationsByEncoding.put(encoder.encodeTableNameAndKey(m), m); } Assert.assertEquals(expectedMutations, new ArrayList<>(mutationsByEncoding.values())); } }
/** * Builds a lexicographically sortable binary key based on a primary key descriptor. * * @param m a spanner mutation. * @return a binary string that preserves the ordering of the primary key. */ public byte[] encodeTableNameAndKey(Mutation m) { OrderedCode orderedCode = new OrderedCode(); orderedCode.writeBytes(m.getTable().getBytes(StandardCharsets.UTF_8)); if (m.getOperation() == Op.DELETE) { if (isPointDelete(m)) { Key next = m.getKeySet().getKeys().iterator().next(); encodeKey(orderedCode, m.getTable(), next); } else { // The key is left empty for non-point deletes, since there is no general way to batch them. } } else { encodeKey(orderedCode, m); } return orderedCode.getEncodedBytes(); }
@ProcessElement public void processElement(ProcessContext c) throws Exception { SpannerSchema spannerSchema = c.sideInput(schemaView); MutationKeyEncoder encoder = new MutationKeyEncoder(spannerSchema); MutationGroup mg = c.element(); long groupSize = MutationSizeEstimator.sizeOf(mg); long groupCells = MutationCellCounter.countOf(spannerSchema, mg); synchronized (this) { if (((batchCells + groupCells) > maxNumMutations) || (batchSizeBytes + groupSize) > maxBatchSizeBytes) { c.output(sortAndGetList()); initSorter(); } mutationsToSort.add(KV.of(encoder.encodeTableNameAndKey(mg.primary()), encode(mg))); batchSizeBytes += groupSize; batchCells += groupCells; } } }
private void encodeKey(OrderedCode orderedCode, Mutation m) { Map<String, Value> mutationMap = mutationAsMap(m); for (SpannerSchema.KeyPart part : schema.getKeyParts(m.getTable())) { Value val = mutationMap.get(part.getField()); switch (code) { case BOOL: writeNumber(orderedCode, part, (long) (val.getBool() ? 0 : 1)); break; case INT64: writeNumber(orderedCode, part, val.getInt64()); break; case FLOAT64: writeNumber(orderedCode, part, Double.doubleToLongBits(val.getFloat64())); break; case STRING: writeString(orderedCode, part, val.getString()); break; case BYTES: writeBytes(orderedCode, part, val.getBytes()); break; case TIMESTAMP: writeTimestamp(orderedCode, part, val.getTimestamp()); break; case DATE: writeNumber(orderedCode, part, encodeDate(val.getDate())); break; default: