Skip to content

Commit a07ff72

Browse files
committed
feat: Add sort and z-order compaction support to r/aws_s3tables_table
1 parent ddc0f64 commit a07ff72

File tree

4 files changed

+283
-3
lines changed

4 files changed

+283
-3
lines changed

.changelog/43923.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resource/aws_s3tables_table: Add `maintenance_configuration.iceberg_compaction.settings.strategy` argument
3+
```

internal/service/s3tables/table.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func (r *tableResource) Schema(ctx context.Context, request resource.SchemaReque
8282
},
8383
// TODO: Once Protocol v6 is supported, convert this to a `schema.SingleNestedAttribute` with full schema information
8484
// Validations needed:
85-
// * iceberg_compaction.settings.target_file_size_mb: int32validator.Between(64, 512)
85+
// * iceberg_compaction.settings.target_file_size_mb: int32validator.Between(64, 512)
8686
// * iceberg_snapshot_management.settings.max_snapshot_age_hours: int32validator.AtLeast(1)
8787
// * iceberg_snapshot_management.settings.min_snapshots_to_keep: int32validator.AtLeast(1)
8888
"maintenance_configuration": schema.ObjectAttribute{
@@ -758,7 +758,8 @@ type tableMaintenanceConfigurationValueModel[T any] struct {
758758
}
759759

760760
type icebergCompactionSettingsModel struct {
761-
TargetFileSizeMB types.Int32 `tfsdk:"target_file_size_mb"`
761+
Strategy fwtypes.StringEnum[awstypes.IcebergCompactionStrategy] `tfsdk:"strategy"`
762+
TargetFileSizeMB types.Int32 `tfsdk:"target_file_size_mb"`
762763
}
763764

764765
type icebergSnapshotManagementSettingsModel struct {

internal/service/s3tables/table_test.go

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func TestAccS3TablesTable_basic(t *testing.T) {
7777
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
7878
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
7979
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
80+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategyAuto),
8081
"target_file_size_mb": knownvalue.Int32Exact(512),
8182
}),
8283
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
@@ -411,6 +412,7 @@ func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) {
411412
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
412413
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
413414
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
415+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategyAuto),
414416
"target_file_size_mb": knownvalue.Int32Exact(64),
415417
}),
416418
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
@@ -441,6 +443,7 @@ func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) {
441443
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
442444
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
443445
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
446+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategyAuto),
444447
"target_file_size_mb": knownvalue.Int32Exact(128),
445448
}),
446449
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
@@ -466,6 +469,107 @@ func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) {
466469
})
467470
}
468471

472+
func TestAccS3TablesTable_compactionStrategy(t *testing.T) {
473+
ctx := acctest.Context(t)
474+
475+
var table s3tables.GetTableOutput
476+
bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
477+
namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_")
478+
rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_")
479+
resourceName := "aws_s3tables_table.test"
480+
481+
resource.ParallelTest(t, resource.TestCase{
482+
PreCheck: func() {
483+
acctest.PreCheck(ctx, t)
484+
testAccPreCheck(ctx, t)
485+
},
486+
ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID),
487+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
488+
CheckDestroy: testAccCheckTableDestroy(ctx),
489+
Steps: []resource.TestStep{
490+
{
491+
Config: testAccTableConfig_compactionStrategyWithSortOrder(rName, namespace, bucketName, "sort"),
492+
Check: resource.ComposeAggregateTestCheckFunc(
493+
testAccCheckTableExists(ctx, resourceName, &table),
494+
),
495+
ConfigStateChecks: []statecheck.StateCheck{
496+
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
497+
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
498+
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
499+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategySort),
500+
"target_file_size_mb": knownvalue.Int32Exact(256),
501+
}),
502+
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
503+
}),
504+
"iceberg_snapshot_management": knownvalue.ObjectExact(map[string]knownvalue.Check{
505+
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
506+
"max_snapshot_age_hours": knownvalue.Int32Exact(72),
507+
"min_snapshots_to_keep": knownvalue.Int32Exact(1),
508+
}),
509+
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
510+
}),
511+
})),
512+
},
513+
},
514+
{
515+
ResourceName: resourceName,
516+
ImportState: true,
517+
ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName),
518+
ImportStateVerify: true,
519+
ImportStateVerifyIdentifierAttribute: names.AttrARN,
520+
},
521+
{
522+
Config: testAccTableConfig_compactionStrategy(rName, namespace, bucketName, "binpack"),
523+
Check: resource.ComposeAggregateTestCheckFunc(
524+
testAccCheckTableExists(ctx, resourceName, &table),
525+
),
526+
ConfigStateChecks: []statecheck.StateCheck{
527+
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
528+
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
529+
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
530+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategyBinpack),
531+
"target_file_size_mb": knownvalue.Int32Exact(256),
532+
}),
533+
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
534+
}),
535+
"iceberg_snapshot_management": knownvalue.ObjectExact(map[string]knownvalue.Check{
536+
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
537+
"max_snapshot_age_hours": knownvalue.Int32Exact(72),
538+
"min_snapshots_to_keep": knownvalue.Int32Exact(1),
539+
}),
540+
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
541+
}),
542+
})),
543+
},
544+
},
545+
{
546+
Config: testAccTableConfig_compactionStrategyWithSortOrder(rName, namespace, bucketName, "z-order"),
547+
Check: resource.ComposeAggregateTestCheckFunc(
548+
testAccCheckTableExists(ctx, resourceName, &table),
549+
),
550+
ConfigStateChecks: []statecheck.StateCheck{
551+
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
552+
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
553+
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
554+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategyZorder),
555+
"target_file_size_mb": knownvalue.Int32Exact(256),
556+
}),
557+
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
558+
}),
559+
"iceberg_snapshot_management": knownvalue.ObjectExact(map[string]knownvalue.Check{
560+
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
561+
"max_snapshot_age_hours": knownvalue.Int32Exact(72),
562+
"min_snapshots_to_keep": knownvalue.Int32Exact(1),
563+
}),
564+
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
565+
}),
566+
})),
567+
},
568+
},
569+
},
570+
})
571+
}
572+
469573
func TestAccS3TablesTable_encryptionConfiguration(t *testing.T) {
470574
ctx := acctest.Context(t)
471575

@@ -515,6 +619,7 @@ func TestAccS3TablesTable_encryptionConfiguration(t *testing.T) {
515619
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("maintenance_configuration"), knownvalue.ObjectExact(map[string]knownvalue.Check{
516620
"iceberg_compaction": knownvalue.ObjectExact(map[string]knownvalue.Check{
517621
"settings": knownvalue.ObjectExact(map[string]knownvalue.Check{
622+
"strategy": tfknownvalue.StringExact(awstypes.IcebergCompactionStrategyAuto),
518623
"target_file_size_mb": knownvalue.Int32Exact(512),
519624
}),
520625
names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled),
@@ -693,6 +798,7 @@ resource "aws_s3tables_table" "test" {
693798
maintenance_configuration = {
694799
iceberg_compaction = {
695800
settings = {
801+
strategy = "auto"
696802
target_file_size_mb = %[4]d
697803
}
698804
status = "enabled"
@@ -722,6 +828,138 @@ resource "aws_s3tables_table_bucket" "test" {
722828
`, rName, namespace, bucketName, targetSize, maxSnapshotAge, minSnapshots)
723829
}
724830

831+
func testAccTableConfig_compactionStrategy(rName, namespace, bucketName, strategy string) string {
832+
return fmt.Sprintf(`
833+
resource "aws_s3tables_table" "test" {
834+
name = %[1]q
835+
namespace = aws_s3tables_namespace.test.namespace
836+
table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn
837+
format = "ICEBERG"
838+
839+
maintenance_configuration = {
840+
iceberg_compaction = {
841+
settings = {
842+
strategy = %[4]q
843+
target_file_size_mb = 256
844+
}
845+
status = "enabled"
846+
}
847+
iceberg_snapshot_management = {
848+
settings = {
849+
max_snapshot_age_hours = 72
850+
min_snapshots_to_keep = 1
851+
}
852+
status = "enabled"
853+
}
854+
}
855+
856+
metadata {
857+
iceberg {
858+
schema {
859+
field {
860+
name = "id"
861+
type = "int"
862+
required = true
863+
}
864+
field {
865+
name = "name"
866+
type = "string"
867+
}
868+
field {
869+
name = "created_at"
870+
type = "timestamp"
871+
required = true
872+
}
873+
}
874+
}
875+
}
876+
}
877+
878+
resource "aws_s3tables_namespace" "test" {
879+
namespace = %[2]q
880+
table_bucket_arn = aws_s3tables_table_bucket.test.arn
881+
882+
lifecycle {
883+
create_before_destroy = true
884+
}
885+
}
886+
887+
resource "aws_s3tables_table_bucket" "test" {
888+
name = %[3]q
889+
}
890+
`, rName, namespace, bucketName, strategy)
891+
}
892+
893+
func testAccTableConfig_compactionStrategyWithSortOrder(rName, namespace, bucketName, strategy string) string {
894+
return fmt.Sprintf(`
895+
resource "aws_s3tables_table" "test" {
896+
name = %[1]q
897+
namespace = aws_s3tables_namespace.test.namespace
898+
table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn
899+
format = "ICEBERG"
900+
901+
maintenance_configuration = {
902+
iceberg_compaction = {
903+
settings = {
904+
strategy = %[4]q
905+
target_file_size_mb = 256
906+
}
907+
status = "enabled"
908+
}
909+
iceberg_snapshot_management = {
910+
settings = {
911+
max_snapshot_age_hours = 72
912+
min_snapshots_to_keep = 1
913+
}
914+
status = "enabled"
915+
}
916+
}
917+
918+
metadata {
919+
iceberg {
920+
schema {
921+
field {
922+
name = "id"
923+
type = "int"
924+
required = true
925+
}
926+
field {
927+
name = "name"
928+
type = "string"
929+
}
930+
field {
931+
name = "created_at"
932+
type = "timestamp"
933+
required = true
934+
}
935+
field {
936+
name = "category"
937+
type = "string"
938+
}
939+
field {
940+
name = "score"
941+
type = "double"
942+
}
943+
}
944+
}
945+
}
946+
}
947+
948+
resource "aws_s3tables_namespace" "test" {
949+
namespace = %[2]q
950+
table_bucket_arn = aws_s3tables_table_bucket.test.arn
951+
952+
lifecycle {
953+
create_before_destroy = true
954+
}
955+
}
956+
957+
resource "aws_s3tables_table_bucket" "test" {
958+
name = %[3]q
959+
}
960+
`, rName, namespace, bucketName, strategy)
961+
}
962+
725963
func testAccTableConfig_encryptionConfiguration(rName, namespace, bucketName string) string {
726964
return fmt.Sprintf(`
727965
resource "aws_s3tables_table" "test" {

website/docs/r/s3tables_table.html.markdown

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,43 @@ resource "aws_s3tables_table_bucket" "example" {
3232
}
3333
```
3434

35+
### With Compaction Strategy
36+
37+
```terraform
38+
resource "aws_s3tables_table" "example" {
39+
name = "example_table"
40+
namespace = aws_s3tables_namespace.example.namespace
41+
table_bucket_arn = aws_s3tables_namespace.example.table_bucket_arn
42+
format = "ICEBERG"
43+
44+
maintenance_configuration = {
45+
iceberg_compaction = {
46+
settings = {
47+
strategy = "z-order"
48+
target_file_size_mb = 256
49+
}
50+
status = "enabled"
51+
}
52+
iceberg_snapshot_management = {
53+
settings = {
54+
max_snapshot_age_hours = 72
55+
min_snapshots_to_keep = 1
56+
}
57+
status = "enabled"
58+
}
59+
}
60+
}
61+
62+
resource "aws_s3tables_namespace" "example" {
63+
namespace = "example_namespace"
64+
table_bucket_arn = aws_s3tables_table_bucket.example.arn
65+
}
66+
67+
resource "aws_s3tables_table_bucket" "example" {
68+
name = "example-bucket"
69+
}
70+
```
71+
3572
### With Metadata Schema
3673

3774
```terraform
@@ -131,8 +168,9 @@ The `iceberg_compaction` object supports the following arguments:
131168

132169
### `iceberg_compaction.settings`
133170

134-
The `iceberg_compaction.settings` object supports the following argument:
171+
The `iceberg_compaction.settings` object supports the following arguments:
135172

173+
* `strategy` - (Optional) The compaction strategy to use for the table. This determines how files are selected and combined during compaction operations. Valid values are `auto`, `binpack`, `sort`, and `z-order`. Defaults to `auto`.
136174
* `target_file_size_mb` - (Required) Data objects smaller than this size may be combined with others to improve query performance.
137175
Must be between `64` and `512`.
138176

0 commit comments

Comments
 (0)