You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by dw...@apache.org on 2020/10/06 23:57:42 UTC

[iceberg] branch master updated: Add TableMetadata.updateSortOrder. (#1551)

This is an automated email from the ASF dual-hosted git repository.

dweeks pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/master by this push:
     new 97568ce  Add TableMetadata.updateSortOrder. (#1551)
97568ce is described below

commit 97568cebfa03d39079308a1c495967c2240829d3
Author: Ryan Blue <bl...@apache.org>
AuthorDate: Tue Oct 6 16:57:30 2020 -0700

    Add TableMetadata.updateSortOrder. (#1551)
---
 .../java/org/apache/iceberg/TableMetadata.java     | 37 +++++++++++++++
 .../java/org/apache/iceberg/TestTableMetadata.java | 53 ++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/core/src/main/java/org/apache/iceberg/TableMetadata.java b/core/src/main/java/org/apache/iceberg/TableMetadata.java
index 566f953..d00e2a8 100644
--- a/core/src/main/java/org/apache/iceberg/TableMetadata.java
+++ b/core/src/main/java/org/apache/iceberg/TableMetadata.java
@@ -491,6 +491,43 @@ public class TableMetadata implements Serializable {
         currentSnapshotId, snapshots, snapshotLog, addPreviousFile(file, lastUpdatedMillis));
   }
 
+  public TableMetadata updateSortOrder(SortOrder newOrder) {
+    SortOrder.checkCompatibility(newOrder, schema);
+
+    // determine the next order id
+    int newOrderId = INITIAL_SORT_ORDER_ID;
+    for (SortOrder order : sortOrders) {
+      if (order.sameOrder(newOrder)) {
+        newOrderId = order.orderId();
+        break;
+      } else if (newOrderId <= order.orderId()) {
+        newOrderId = order.orderId() + 1;
+      }
+    }
+
+    if (newOrderId == defaultSortOrderId) {
+      return this;
+    }
+
+    ImmutableList.Builder<SortOrder> builder = ImmutableList.builder();
+    builder.addAll(sortOrders);
+
+    if (!sortOrdersById.containsKey(newOrderId)) {
+      if (newOrder.isUnsorted()) {
+        newOrderId = SortOrder.unsorted().orderId();
+        builder.add(SortOrder.unsorted());
+      } else {
+        // rebuild the sort order using new column ids
+        builder.add(freshSortOrder(newOrderId, schema, newOrder));
+      }
+    }
+
+    return new TableMetadata(null, formatVersion, uuid, location,
+        lastSequenceNumber, System.currentTimeMillis(), lastColumnId, schema, defaultSpecId, specs,
+        newOrderId, builder.build(), properties, currentSnapshotId, snapshots, snapshotLog,
+        addPreviousFile(file, lastUpdatedMillis));
+  }
+
   public TableMetadata addStagedSnapshot(Snapshot snapshot) {
     ValidationException.check(formatVersion == 1 || snapshot.sequenceNumber() > lastSequenceNumber,
         "Cannot add snapshot with sequence number %s older than last sequence number %s",
diff --git a/core/src/test/java/org/apache/iceberg/TestTableMetadata.java b/core/src/test/java/org/apache/iceberg/TestTableMetadata.java
index 38512de..6d188fa 100644
--- a/core/src/test/java/org/apache/iceberg/TestTableMetadata.java
+++ b/core/src/test/java/org/apache/iceberg/TestTableMetadata.java
@@ -550,4 +550,57 @@ public class TestTableMetadata {
         ValidationException.class, "Spec does not use sequential IDs that are required in v1",
         () -> metadata.updatePartitionSpec(spec));
   }
+
+  @Test
+  public void testSortOrder() {
+    Schema schema = new Schema(
+        Types.NestedField.required(10, "x", Types.StringType.get())
+    );
+
+    TableMetadata meta = TableMetadata.newTableMetadata(
+        schema, PartitionSpec.unpartitioned(), null, ImmutableMap.of());
+    Assert.assertTrue("Should default to unsorted order", meta.sortOrder().isUnsorted());
+    Assert.assertSame("Should detect identical unsorted order", meta, meta.updateSortOrder(SortOrder.unsorted()));
+  }
+
+  @Test
+  public void testUpdateSortOrder() {
+    Schema schema = new Schema(
+        Types.NestedField.required(10, "x", Types.StringType.get())
+    );
+
+    SortOrder order = SortOrder.builderFor(schema).asc("x").build();
+
+    TableMetadata sortedByX = TableMetadata.newTableMetadata(
+        schema, PartitionSpec.unpartitioned(), order, null, ImmutableMap.of());
+    Assert.assertEquals("Should have 1 sort order", 1, sortedByX.sortOrders().size());
+    Assert.assertEquals("Should use orderId 1", 1, sortedByX.sortOrder().orderId());
+    Assert.assertEquals("Should be sorted by one field", 1, sortedByX.sortOrder().fields().size());
+    Assert.assertEquals("Should use the table's field ids", 1, sortedByX.sortOrder().fields().get(0).sourceId());
+    Assert.assertEquals("Should be ascending",
+        SortDirection.ASC, sortedByX.sortOrder().fields().get(0).direction());
+    Assert.assertEquals("Should be nulls first",
+        NullOrder.NULLS_FIRST, sortedByX.sortOrder().fields().get(0).nullOrder());
+
+    // build an equivalent order with the correct schema
+    SortOrder newOrder = SortOrder.builderFor(sortedByX.schema()).asc("x").build();
+
+    TableMetadata alsoSortedByX = sortedByX.updateSortOrder(newOrder);
+    Assert.assertSame("Should detect current sortOrder and not update", alsoSortedByX, sortedByX);
+
+    TableMetadata unsorted = alsoSortedByX.updateSortOrder(SortOrder.unsorted());
+    Assert.assertEquals("Should have 2 sort orders", 2, unsorted.sortOrders().size());
+    Assert.assertEquals("Should use orderId 0", 0, unsorted.sortOrder().orderId());
+    Assert.assertTrue("Should be unsorted", unsorted.sortOrder().isUnsorted());
+
+    TableMetadata sortedByXDesc = unsorted.updateSortOrder(SortOrder.builderFor(unsorted.schema()).desc("x").build());
+    Assert.assertEquals("Should have 3 sort orders", 3, sortedByXDesc.sortOrders().size());
+    Assert.assertEquals("Should use orderId 2", 2, sortedByXDesc.sortOrder().orderId());
+    Assert.assertEquals("Should be sorted by one field", 1, sortedByXDesc.sortOrder().fields().size());
+    Assert.assertEquals("Should use the table's field ids", 1, sortedByXDesc.sortOrder().fields().get(0).sourceId());
+    Assert.assertEquals("Should be ascending",
+        SortDirection.DESC, sortedByXDesc.sortOrder().fields().get(0).direction());
+    Assert.assertEquals("Should be nulls first",
+        NullOrder.NULLS_FIRST, sortedByX.sortOrder().fields().get(0).nullOrder());
+  }
 }