Skip to content

Commit b7fe83f

Browse files
committed
init plan
1 parent e16d6d4 commit b7fe83f

File tree

2 files changed

+1571
-0
lines changed

2 files changed

+1571
-0
lines changed

TABLES_ARCHITECTURE_DECISION.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Architectural Decision: Feature Subdirectory for S3 Tables
2+
3+
## Decision
4+
5+
S3 Tables support will be implemented in a **feature subdirectory** `src/s3/tables/` rather than mixing with the existing flat S3 module structure.
6+
7+
## Context
8+
9+
The existing MinIO Rust SDK uses a flat structure under `src/s3/`:
10+
- `src/s3/builders/` - All S3 operation builders (50+ files)
11+
- `src/s3/client/` - All S3 client methods (50+ files)
12+
- `src/s3/response/` - All S3 response types (50+ files)
13+
14+
Each S3 operation (e.g., `CreateBucket`, `PutObject`, `GetObject`) has three corresponding files across these directories.
15+
16+
## Rationale for Subdirectory Approach
17+
18+
We chose to use a subdirectory `src/s3/tables/` with its own nested `builders/`, `client/`, and `response/` directories for the following reasons:
19+
20+
### 1. Separate API Surface
21+
22+
S3 Tables is a completely distinct API:
23+
- **Different base path**: `/tables/v1/*` vs standard S3 paths
24+
- **Different semantics**: Catalog/metadata operations vs object storage operations
25+
- **Different concepts**: Warehouses, namespaces, tables vs buckets and objects
26+
27+
### 2. Different Client Type
28+
29+
Tables operations use `TablesClient` (which wraps `MinioClient`) rather than direct `MinioClient` methods:
30+
31+
```rust
32+
// S3 operations (existing)
33+
let response = client.put_object("bucket", "key")
34+
.build()
35+
.send()
36+
.await?;
37+
38+
// Tables operations (new)
39+
let tables = TablesClient::new(client);
40+
let response = tables.create_table("warehouse", "namespace", "table")
41+
.schema(schema)
42+
.build()
43+
.send()
44+
.await?;
45+
```
46+
47+
This creates a natural API boundary and prevents confusion.
48+
49+
### 3. Distinct Authentication
50+
51+
Tables uses different authentication:
52+
- **Service name**: `s3tables` vs `s3`
53+
- **Policy actions**: `s3tables:CreateTable`, `s3tables:CreateWarehouse` vs `s3:PutObject`, `s3:CreateBucket`
54+
- **Resource format**: `bucket/{warehouse}/table` vs `bucket/key`
55+
56+
### 4. Substantial Type System
57+
58+
Iceberg schema types form a significant type hierarchy that deserves isolated organization:
59+
- `Schema`, `Field`, `FieldType`, `StructType`, `ListType`, `MapType`
60+
- `PartitionSpec`, `PartitionField`, `Transform`
61+
- `SortOrder`, `SortField`, `SortDirection`
62+
- `Requirement` (10+ variants)
63+
- `Update` (12+ variants)
64+
- `Snapshot`, `SnapshotRef`
65+
- Table metadata structures
66+
67+
These types are specific to Iceberg and don't overlap with S3 concepts.
68+
69+
### 5. Feature Flag Potential
70+
71+
The subdirectory structure enables future feature-flagging:
72+
73+
```toml
74+
[features]
75+
default = []
76+
tables = [] # Optional S3 Tables / Iceberg support
77+
```
78+
79+
This allows users to opt-out of Tables support if they only need basic S3 operations, reducing compile time and binary size.
80+
81+
### 6. Cognitive Load
82+
83+
Mixing operations would create significant navigation challenges:
84+
- **S3 operations**: ~50 existing operations
85+
- **Tables operations**: ~20 new operations
86+
- **Total in flat structure**: ~70 files in each of `builders/`, `client/`, `response/`
87+
88+
The subdirectory approach keeps related code together and makes it easier to understand the codebase.
89+
90+
### 7. Clear Boundaries
91+
92+
Developers can easily distinguish:
93+
- **S3 operations**: `use minio::s3::{MinioClient, builders::*}`
94+
- **Tables operations**: `use minio::s3::tables::{TablesClient, builders::*}`
95+
96+
The import paths immediately convey which API surface is being used.
97+
98+
## Alternative Considered: Flat Structure
99+
100+
We considered maintaining the flat structure:
101+
102+
```
103+
src/s3/
104+
├── builders/
105+
│ ├── put_object.rs # Existing S3
106+
│ ├── get_object.rs # Existing S3
107+
│ ├── create_warehouse.rs # New Tables
108+
│ ├── create_table.rs # New Tables
109+
│ └── ... (70+ files total)
110+
```
111+
112+
**Rejected because**:
113+
- Mixes two conceptually different APIs in the same namespace
114+
- `TablesClient` methods would need to reach across module boundaries
115+
- Harder to feature-flag or maintain separately
116+
- Increased cognitive load when navigating codebase
117+
- Blurs the distinction between object storage and table catalog operations
118+
119+
## Implementation Structure
120+
121+
The chosen structure:
122+
123+
```
124+
src/s3/
125+
├── tables/ # ← Feature subdirectory
126+
│ ├── mod.rs # Export TablesClient, types
127+
│ ├── client.rs # TablesClient definition
128+
│ ├── types.rs # Tables-specific types
129+
│ ├── error.rs # TablesError enum
130+
│ ├── iceberg.rs # Iceberg schema types
131+
│ ├── builders/
132+
│ │ ├── mod.rs
133+
│ │ ├── create_warehouse.rs
134+
│ │ ├── create_table.rs
135+
│ │ └── ... (~20 files)
136+
│ ├── client/
137+
│ │ ├── mod.rs
138+
│ │ ├── create_warehouse.rs
139+
│ │ ├── create_table.rs
140+
│ │ └── ... (~20 files)
141+
│ └── response/
142+
│ ├── mod.rs
143+
│ ├── create_warehouse.rs
144+
│ ├── create_table.rs
145+
│ └── ... (~20 files)
146+
```
147+
148+
## Benefits
149+
150+
1. **Modularity**: Tables can be maintained, tested, and documented independently
151+
2. **Clarity**: Import paths clearly indicate API surface
152+
3. **Scalability**: Future additions (views, materialized views) can be added to `tables/` module
153+
4. **Feature flags**: Easy to make Tables support optional
154+
5. **Cognitive boundaries**: Developers know where to find Tables-specific code
155+
6. **Type isolation**: Iceberg types don't pollute S3 namespace
156+
157+
## Precedent
158+
159+
This pattern is common in Rust ecosystems:
160+
- `tokio` has separate `tokio::net`, `tokio::fs`, `tokio::sync` modules
161+
- `aws-sdk-rust` has separate crates for each service
162+
- `rusoto` had separate sub-crates per AWS service
163+
164+
## Decision Date
165+
166+
October 2024
167+
168+
## Status
169+
170+
**Accepted** - To be implemented in Phase 1 of Tables support.

0 commit comments

Comments
 (0)