41
41
import org .apache .iceberg .exceptions .NoSuchTableException ;
42
42
import org .apache .iceberg .hadoop .HadoopFileIO ;
43
43
import org .apache .iceberg .io .FileIO ;
44
+ import org .apache .iceberg .relocated .com .google .common .annotations .VisibleForTesting ;
44
45
import org .apache .iceberg .relocated .com .google .common .base .Joiner ;
46
+ import org .apache .iceberg .relocated .com .google .common .base .Preconditions ;
45
47
import org .apache .iceberg .relocated .com .google .common .collect .ImmutableMap ;
46
48
import org .apache .iceberg .util .Tasks ;
47
- import org .projectnessie .api .TreeApi ;
48
- import org .projectnessie .api .params .EntriesParams ;
49
- import org .projectnessie .client .NessieClient ;
50
49
import org .projectnessie .client .NessieConfigConstants ;
50
+ import org .projectnessie .client .api .CommitMultipleOperationsBuilder ;
51
+ import org .projectnessie .client .api .NessieApiV1 ;
52
+ import org .projectnessie .client .http .HttpClientBuilder ;
51
53
import org .projectnessie .client .http .HttpClientException ;
52
54
import org .projectnessie .error .BaseNessieClientServerException ;
53
55
import org .projectnessie .error .NessieConflictException ;
54
56
import org .projectnessie .error .NessieNotFoundException ;
55
57
import org .projectnessie .model .Branch ;
56
- import org .projectnessie .model .Contents ;
58
+ import org .projectnessie .model .Content ;
59
+ import org .projectnessie .model .ContentKey ;
57
60
import org .projectnessie .model .IcebergTable ;
58
- import org .projectnessie .model .ImmutableDelete ;
59
- import org .projectnessie .model .ImmutableOperations ;
60
- import org .projectnessie .model .ImmutablePut ;
61
- import org .projectnessie .model .Operations ;
61
+ import org .projectnessie .model .Operation ;
62
62
import org .projectnessie .model .Reference ;
63
+ import org .projectnessie .model .TableReference ;
64
+ import org .projectnessie .model .Tag ;
63
65
import org .slf4j .Logger ;
64
66
import org .slf4j .LoggerFactory ;
65
67
75
77
public class NessieCatalog extends BaseMetastoreCatalog implements AutoCloseable , SupportsNamespaces , Configurable {
76
78
private static final Logger logger = LoggerFactory .getLogger (NessieCatalog .class );
77
79
private static final Joiner SLASH = Joiner .on ("/" );
78
- private NessieClient client ;
80
+ private NessieApiV1 api ;
79
81
private String warehouseLocation ;
80
82
private Configuration config ;
81
83
private UpdateableReference reference ;
@@ -95,7 +97,8 @@ public void initialize(String inputName, Map<String, String> options) {
95
97
// remove nessie prefix
96
98
final Function <String , String > removePrefix = x -> x .replace ("nessie." , "" );
97
99
98
- this .client = NessieClient .builder ().fromConfig (x -> options .get (removePrefix .apply (x ))).build ();
100
+ this .api = HttpClientBuilder .builder ().fromConfig (x -> options .get (removePrefix .apply (x )))
101
+ .build (NessieApiV1 .class );
99
102
100
103
this .warehouseLocation = options .get (CatalogProperties .WAREHOUSE_LOCATION );
101
104
if (warehouseLocation == null ) {
@@ -120,12 +123,12 @@ public void initialize(String inputName, Map<String, String> options) {
120
123
throw new IllegalStateException ("Parameter 'warehouse' not set, Nessie can't store data." );
121
124
}
122
125
final String requestedRef = options .get (removePrefix .apply (NessieConfigConstants .CONF_NESSIE_REF ));
123
- this .reference = loadReference (requestedRef );
126
+ this .reference = loadReference (requestedRef , null );
124
127
}
125
128
126
129
@ Override
127
130
public void close () {
128
- client .close ();
131
+ api .close ();
129
132
}
130
133
131
134
@ Override
@@ -135,15 +138,17 @@ public String name() {
135
138
136
139
@ Override
137
140
protected TableOperations newTableOps (TableIdentifier tableIdentifier ) {
138
- TableReference pti = TableReference .parse (tableIdentifier );
141
+ TableReference tr = TableReference .parse (tableIdentifier .name ());
142
+ Preconditions .checkArgument (!tr .hasTimestamp (), "Invalid table name: # is only allowed for hashes (reference by " +
143
+ "timestamp is not supported)" );
139
144
UpdateableReference newReference = this .reference ;
140
- if (pti . reference () != null ) {
141
- newReference = loadReference (pti . reference ());
145
+ if (tr . getReference () != null ) {
146
+ newReference = loadReference (tr . getReference (), tr . getHash ());
142
147
}
143
148
return new NessieTableOperations (
144
- NessieUtil . toKey ( pti . tableIdentifier ()),
149
+ ContentKey . of ( org . projectnessie . model . Namespace . of ( tableIdentifier . namespace (). levels ()), tr . getName ()),
145
150
newReference ,
146
- client ,
151
+ api ,
147
152
fileIO ,
148
153
catalogOptions );
149
154
}
@@ -170,23 +175,27 @@ public boolean dropTable(TableIdentifier identifier, boolean purge) {
170
175
return false ;
171
176
}
172
177
173
- Operations contents = ImmutableOperations .builder ()
174
- .addOperations (ImmutableDelete .builder ().key (NessieUtil .toKey (identifier )).build ())
175
- .commitMeta (NessieUtil .buildCommitMetadata (String .format ("iceberg delete table '%s'" , identifier ),
178
+ if (purge ) {
179
+ logger .info ("Purging data for table {} was set to true but is ignored" , identifier .toString ());
180
+ }
181
+
182
+ CommitMultipleOperationsBuilder commitBuilderBase = api .commitMultipleOperations ()
183
+ .commitMeta (NessieUtil .buildCommitMetadata (String .format ("Iceberg delete table %s" , identifier ),
176
184
catalogOptions ))
177
- .build ( );
185
+ .operation ( Operation . Delete . of ( NessieUtil . toKey ( identifier )) );
178
186
179
187
// We try to drop the table. Simple retry after ref update.
180
188
boolean threw = true ;
181
189
try {
182
- Tasks .foreach (contents )
190
+ Tasks .foreach (commitBuilderBase )
183
191
.retry (5 )
184
192
.stopRetryOn (NessieNotFoundException .class )
185
193
.throwFailureWhenFinished ()
186
- .onFailure ((c , exception ) -> refresh ())
187
- .run (c -> {
188
- Branch branch = client .getTreeApi ().commitMultipleOperations (reference .getAsBranch ().getName (),
189
- reference .getHash (), c );
194
+ .onFailure ((o , exception ) -> refresh ())
195
+ .run (commitBuilder -> {
196
+ Branch branch = commitBuilder
197
+ .branch (reference .getAsBranch ())
198
+ .commit ();
190
199
reference .updateReference (branch );
191
200
}, BaseNessieClientServerException .class );
192
201
threw = false ;
@@ -215,24 +224,22 @@ public void renameTable(TableIdentifier from, TableIdentifier toOriginal) {
215
224
throw new AlreadyExistsException ("table %s already exists" , to .name ());
216
225
}
217
226
218
- Operations contents = ImmutableOperations .builder ()
219
- .addOperations (
220
- ImmutablePut .builder ().key (NessieUtil .toKey (to )).contents (existingFromTable ).build (),
221
- ImmutableDelete .builder ().key (NessieUtil .toKey (from )).build ())
222
- .commitMeta (NessieUtil .buildCommitMetadata (String .format ("iceberg rename table from '%s' to '%s'" ,
223
- from , to ),
224
- catalogOptions ))
225
- .build ();
227
+ CommitMultipleOperationsBuilder operations = api .commitMultipleOperations ()
228
+ .commitMeta (NessieUtil .buildCommitMetadata (String .format ("Iceberg rename table from '%s' to '%s'" ,
229
+ from , to ), catalogOptions ))
230
+ .operation (Operation .Put .of (NessieUtil .toKey (to ), existingFromTable , existingFromTable ))
231
+ .operation (Operation .Delete .of (NessieUtil .toKey (from )));
226
232
227
233
try {
228
- Tasks .foreach (contents )
234
+ Tasks .foreach (operations )
229
235
.retry (5 )
230
236
.stopRetryOn (NessieNotFoundException .class )
231
237
.throwFailureWhenFinished ()
232
- .onFailure ((c , exception ) -> refresh ())
233
- .run (c -> {
234
- Branch branch = client .getTreeApi ().commitMultipleOperations (reference .getAsBranch ().getName (),
235
- reference .getHash (), c );
238
+ .onFailure ((o , exception ) -> refresh ())
239
+ .run (ops -> {
240
+ Branch branch = ops
241
+ .branch (reference .getAsBranch ())
242
+ .commit ();
236
243
reference .updateReference (branch );
237
244
}, BaseNessieClientServerException .class );
238
245
} catch (NessieNotFoundException e ) {
@@ -322,37 +329,46 @@ public Configuration getConf() {
322
329
return config ;
323
330
}
324
331
325
- TreeApi getTreeApi () {
326
- return client .getTreeApi ();
327
- }
328
-
329
332
public void refresh () throws NessieNotFoundException {
330
- reference .refresh ();
333
+ reference .refresh (api );
331
334
}
332
335
333
336
public String currentHash () {
334
337
return reference .getHash ();
335
338
}
336
339
340
+ @ VisibleForTesting
337
341
String currentRefName () {
338
342
return reference .getName ();
339
343
}
340
344
345
+ @ VisibleForTesting
346
+ FileIO fileIO () {
347
+ return fileIO ;
348
+ }
349
+
341
350
private IcebergTable table (TableIdentifier tableIdentifier ) {
342
351
try {
343
- Contents table = client . getContentsApi ()
344
- . getContents ( NessieUtil . toKey ( tableIdentifier ), reference . getName (), reference . getHash () );
345
- return table .unwrap (IcebergTable .class ).orElse (null );
352
+ ContentKey key = NessieUtil . toKey ( tableIdentifier );
353
+ Content table = api . getContent (). key ( key ). reference ( reference . getReference ()). get (). get ( key );
354
+ return table != null ? table .unwrap (IcebergTable .class ).orElse (null ) : null ;
346
355
} catch (NessieNotFoundException e ) {
347
356
return null ;
348
357
}
349
358
}
350
359
351
- private UpdateableReference loadReference (String requestedRef ) {
360
+ private UpdateableReference loadReference (String requestedRef , String hash ) {
352
361
try {
353
- Reference ref = requestedRef == null ? client .getTreeApi ().getDefaultBranch ()
354
- : client .getTreeApi ().getReferenceByName (requestedRef );
355
- return new UpdateableReference (ref , client .getTreeApi ());
362
+ Reference ref = requestedRef == null ? api .getDefaultBranch ()
363
+ : api .getReference ().refName (requestedRef ).get ();
364
+ if (hash != null ) {
365
+ if (ref instanceof Branch ) {
366
+ ref = Branch .of (ref .getName (), hash );
367
+ } else {
368
+ ref = Tag .of (ref .getName (), hash );
369
+ }
370
+ }
371
+ return new UpdateableReference (ref , hash != null );
356
372
} catch (NessieNotFoundException ex ) {
357
373
if (requestedRef != null ) {
358
374
throw new IllegalArgumentException (String .format (
@@ -369,8 +385,9 @@ private UpdateableReference loadReference(String requestedRef) {
369
385
370
386
private Stream <TableIdentifier > tableStream (Namespace namespace ) {
371
387
try {
372
- return client .getTreeApi ()
373
- .getEntries (reference .getName (), EntriesParams .builder ().hashOnRef (reference .getHash ()).build ())
388
+ return api .getEntries ()
389
+ .reference (reference .getReference ())
390
+ .get ()
374
391
.getEntries ()
375
392
.stream ()
376
393
.filter (NessieUtil .namespacePredicate (namespace ))
0 commit comments