22
22
import com .starrocks .catalog .PartitionKey ;
23
23
import com .starrocks .catalog .Table ;
24
24
import com .starrocks .catalog .Type ;
25
+ import com .starrocks .common .Config ;
25
26
import com .starrocks .connector .ColumnTypeConverter ;
26
27
import com .starrocks .connector .ConnectorMetadatRequestContext ;
27
28
import com .starrocks .connector .ConnectorMetadata ;
45
46
import com .starrocks .sql .optimizer .statistics .Statistics ;
46
47
import org .apache .logging .log4j .LogManager ;
47
48
import org .apache .logging .log4j .Logger ;
49
+ import org .apache .paimon .catalog .CachingCatalog ;
48
50
import org .apache .paimon .catalog .Catalog ;
49
51
import org .apache .paimon .catalog .Identifier ;
50
52
import org .apache .paimon .data .InternalRow ;
53
+ import org .apache .paimon .data .Timestamp ;
51
54
import org .apache .paimon .predicate .Predicate ;
52
55
import org .apache .paimon .predicate .PredicateBuilder ;
53
56
import org .apache .paimon .reader .RecordReader ;
54
57
import org .apache .paimon .reader .RecordReaderIterator ;
55
58
import org .apache .paimon .table .source .ReadBuilder ;
56
59
import org .apache .paimon .table .source .Split ;
57
- import org .apache .paimon .table .system .PartitionsTable ;
58
60
import org .apache .paimon .table .system .SchemasTable ;
59
61
import org .apache .paimon .table .system .SnapshotsTable ;
60
62
import org .apache .paimon .types .DataField ;
63
65
import org .apache .paimon .types .DateType ;
64
66
import org .apache .paimon .types .RowType ;
65
67
import org .apache .paimon .utils .DateTimeUtils ;
68
+ import org .apache .paimon .utils .PartitionPathUtils ;
66
69
67
70
import java .util .ArrayList ;
71
+ import java .util .Arrays ;
72
+ import java .util .HashMap ;
68
73
import java .util .List ;
69
74
import java .util .Map ;
70
75
import java .util .concurrent .ConcurrentHashMap ;
@@ -80,7 +85,7 @@ public class PaimonMetadata implements ConnectorMetadata {
80
85
private final Map <Identifier , Table > tables = new ConcurrentHashMap <>();
81
86
private final Map <String , Database > databases = new ConcurrentHashMap <>();
82
87
private final Map <PredicateSearchKey , PaimonSplitsInfo > paimonSplits = new ConcurrentHashMap <>();
83
- private final Map <String , Long > partitionInfos = new ConcurrentHashMap <>();
88
+ private final Map <String , Partition > partitionInfos = new ConcurrentHashMap <>();
84
89
private final ConnectorProperties properties ;
85
90
86
91
public PaimonMetadata (String catalogName , HdfsEnvironment hdfsEnvironment , Catalog paimonNativeCatalog ,
@@ -130,54 +135,54 @@ private void updatePartitionInfo(String databaseName, String tableName) {
130
135
partitionColumnTypes .add (dataTableRowType .getTypeAt (dataTableRowType .getFieldIndex (partitionColumnName )));
131
136
}
132
137
133
- Identifier partitionTableIdentifier = new Identifier (databaseName , String .format ("%s%s" , tableName , "$partitions" ));
134
- RecordReaderIterator <InternalRow > iterator = null ;
135
138
try {
136
- PartitionsTable table = (PartitionsTable ) paimonNativeCatalog .getTable (partitionTableIdentifier );
137
- RowType partitionTableRowType = table .rowType ();
138
- DataType lastUpdateTimeType = partitionTableRowType .getTypeAt (partitionTableRowType
139
- .getFieldIndex ("last_update_time" ));
140
- int [] projected = new int [] {0 , 4 };
141
- RecordReader <InternalRow > recordReader = table .newReadBuilder ().withProjection (projected )
142
- .newRead ().createReader (table .newScan ().plan ());
143
- iterator = new RecordReaderIterator <>(recordReader );
144
- while (iterator .hasNext ()) {
145
- InternalRow rowData = iterator .next ();
146
- String partition = rowData .getString (0 ).toString ();
147
- org .apache .paimon .data .Timestamp lastUpdateTime = rowData .getTimestamp (1 ,
148
- DataTypeChecks .getPrecision (lastUpdateTimeType ));
149
- String [] partitionValues = partition .replace ("[" , "" ).replace ("]" , "" )
150
- .split ("," );
151
- if (partitionValues .length != partitionColumnNames .size ()) {
152
- String errorMsg = String .format ("The length of partitionValues %s is not equal to " +
153
- "the partitionColumnNames %s." , partitionValues .length , partitionColumnNames .size ());
154
- throw new IllegalArgumentException (errorMsg );
155
- }
156
- StringBuilder sb = new StringBuilder ();
157
- for (int i = 0 ; i < partitionValues .length ; i ++) {
158
- String column = partitionColumnNames .get (i );
159
- String value = partitionValues [i ].trim ();
160
- if (partitionColumnTypes .get (i ) instanceof DateType ) {
161
- value = DateTimeUtils .formatDate (Integer .parseInt (value ));
162
- }
163
- sb .append (column ).append ("=" ).append (value );
164
- sb .append ("/" );
165
- }
166
- sb .deleteCharAt (sb .length () - 1 );
167
- String partitionName = sb .toString ();
168
- this .partitionInfos .put (partitionName , lastUpdateTime .getMillisecond ());
139
+ List <org .apache .paimon .partition .Partition > partitions = paimonNativeCatalog .listPartitions (identifier );
140
+ for (org .apache .paimon .partition .Partition partition : partitions ) {
141
+ String partitionPath = PartitionPathUtils
142
+ .generatePartitionPath (partition .spec (), dataTableRowType );
143
+ String [] partitionValues = Arrays .stream (partitionPath .split ("/" ))
144
+ .map (part -> part .split ("=" )[1 ])
145
+ .toArray (String []::new );
146
+ Partition srPartition = getPartition (partition .recordCount (),
147
+ partition .fileSizeInBytes (), partition .fileCount (),
148
+ partitionColumnNames , partitionColumnTypes , partitionValues ,
149
+ Timestamp .fromEpochMillis (partition .lastFileCreationTime ()));
150
+ this .partitionInfos .put (srPartition .getPartitionName (), srPartition );
169
151
}
170
- } catch (Exception e ) {
152
+ return ;
153
+ } catch (Catalog .TableNotExistException e ) {
171
154
LOG .error ("Failed to update partition info of paimon table {}.{}." , databaseName , tableName , e );
172
- } finally {
173
- if (iterator != null ) {
174
- try {
175
- iterator .close ();
176
- } catch (Exception e ) {
177
- LOG .error ("Failed to update partition info of paimon table {}.{}." , databaseName , tableName , e );
178
- }
155
+ }
156
+ }
157
+
158
+ private Partition getPartition (Long recordCount ,
159
+ Long fileSizeInBytes ,
160
+ Long fileCount ,
161
+ List <String > partitionColumnNames ,
162
+ List <DataType > partitionColumnTypes ,
163
+ String [] partitionValues ,
164
+ org .apache .paimon .data .Timestamp lastUpdateTime ) {
165
+ if (partitionValues .length != partitionColumnNames .size ()) {
166
+ String errorMsg = String .format ("The length of partitionValues %s is not equal to " +
167
+ "the partitionColumnNames %s." , partitionValues .length , partitionColumnNames .size ());
168
+ throw new IllegalArgumentException (errorMsg );
169
+ }
170
+
171
+ StringBuilder sb = new StringBuilder ();
172
+ for (int i = 0 ; i < partitionValues .length ; i ++) {
173
+ String column = partitionColumnNames .get (i );
174
+ String value = partitionValues [i ].trim ();
175
+ if (partitionColumnTypes .get (i ) instanceof DateType ) {
176
+ value = DateTimeUtils .formatDate (Integer .parseInt (value ));
179
177
}
178
+ sb .append (column ).append ("=" ).append (value );
179
+ sb .append ("/" );
180
180
}
181
+ sb .deleteCharAt (sb .length () - 1 );
182
+ String partitionName = sb .toString ();
183
+
184
+ return new Partition (partitionName , fileCount );
185
+
181
186
}
182
187
183
188
@ Override
@@ -348,7 +353,7 @@ public long getTableCreateTime(String dbName, String tblName) {
348
353
DataType updateTimeType = rowType .getTypeAt (rowType .getFieldIndex ("update_time" ));
349
354
int [] projected = new int [] {0 , 6 };
350
355
PredicateBuilder predicateBuilder = new PredicateBuilder (rowType );
351
- Predicate equal = predicateBuilder .equal (predicateBuilder .indexOf ("schema_id" ), 0 );
356
+ Predicate equal = predicateBuilder .equal (predicateBuilder .indexOf ("schema_id" ), 0L );
352
357
RecordReader <InternalRow > recordReader = table .newReadBuilder ().withProjection (projected )
353
358
.withFilter (equal ).newRead ().createReader (table .newScan ().plan ());
354
359
iterator = new RecordReaderIterator <>(recordReader );
@@ -429,11 +434,57 @@ public List<PartitionInfo> getPartitions(Table table, List<String> partitionName
429
434
this .updatePartitionInfo (paimonTable .getCatalogDBName (), paimonTable .getCatalogTableName ());
430
435
}
431
436
if (this .partitionInfos .get (partitionName ) != null ) {
432
- result .add (new Partition ( partitionName , this .partitionInfos .get (partitionName ) ));
437
+ result .add (this .partitionInfos .get (partitionName ));
433
438
} else {
434
439
LOG .warn ("Cannot find the paimon partition info: {}" , partitionName );
435
440
}
436
441
}
437
442
return result ;
438
443
}
444
+
445
+ @ Override
446
+ public void refreshTable (String srDbName , Table table , List <String > partitionNames , boolean onlyCachedPartitions ) {
447
+ String tableName = table .getCatalogTableName ();
448
+ Identifier identifier = new Identifier (srDbName , tableName );
449
+ paimonNativeCatalog .invalidateTable (identifier );
450
+ try {
451
+ ((PaimonTable ) table ).setPaimonNativeTable (paimonNativeCatalog .getTable (identifier ));
452
+ if (partitionNames != null && !partitionNames .isEmpty ()) {
453
+ // todo: do not support refresh an exact partition
454
+ this .refreshPartitionInfo (identifier );
455
+ } else {
456
+ this .refreshPartitionInfo (identifier );
457
+ }
458
+ // Preheat manifest files, disabled by default
459
+ if (Config .enable_paimon_refresh_manifest_files ) {
460
+ if (partitionNames == null || partitionNames .isEmpty ()) {
461
+ ((PaimonTable ) table ).getNativeTable ().newReadBuilder ().newScan ().plan ();
462
+ } else {
463
+ List <String > partitionColumnNames = table .getPartitionColumnNames ();
464
+ Map <String , String > partitionSpec = new HashMap <>();
465
+ for (String partitionName : partitionNames ) {
466
+ partitionSpec .put (String .join ("," , partitionColumnNames ), partitionName );
467
+ }
468
+ ((PaimonTable ) table ).getNativeTable ().newReadBuilder ()
469
+ .withPartitionFilter (partitionSpec ).newScan ().plan ();
470
+ }
471
+ }
472
+ tables .put (identifier , table );
473
+ } catch (Exception e ) {
474
+ LOG .error ("Failed to refresh table {}.{}.{}." , catalogName , srDbName , tableName , e );
475
+ }
476
+ }
477
+
478
+ private void refreshPartitionInfo (Identifier identifier ) {
479
+ if (paimonNativeCatalog instanceof CachingCatalog ) {
480
+ try {
481
+ paimonNativeCatalog .invalidateTable (identifier );
482
+ ((CachingCatalog ) paimonNativeCatalog ).refreshPartitions (identifier );
483
+ } catch (Catalog .TableNotExistException e ) {
484
+ throw new RuntimeException (e );
485
+ }
486
+ } else {
487
+ LOG .warn ("Current catalog {} does not support cache." , catalogName );
488
+ }
489
+ }
439
490
}
0 commit comments