2222import org .apache .paimon .catalog .Identifier ;
2323import org .apache .paimon .fs .FileIO ;
2424import org .apache .paimon .fs .Path ;
25- import org .apache .paimon .options .Options ;
2625import org .apache .paimon .rest .RESTApi ;
27- import org .apache .paimon .rest .RESTUtil ;
26+ import org .apache .paimon .rest .RESTTokenFileIO ;
2827import org .apache .paimon .rest .exceptions .AlreadyExistsException ;
2928import org .apache .paimon .rest .exceptions .BadRequestException ;
3029import org .apache .paimon .rest .exceptions .ForbiddenException ;
3130import org .apache .paimon .rest .exceptions .NoSuchResourceException ;
3231import org .apache .paimon .rest .exceptions .NotImplementedException ;
3332import org .apache .paimon .rest .responses .GetDatabaseResponse ;
3433import org .apache .paimon .rest .responses .GetTableResponse ;
35- import org .apache .paimon .rest .responses .GetTableTokenResponse ;
3634import org .apache .paimon .schema .Schema ;
37- import org .apache .paimon .utils .IOUtils ;
38- import org .apache .paimon .utils .ThreadUtils ;
39-
40- import org .apache .paimon .shade .caffeine2 .com .github .benmanes .caffeine .cache .Cache ;
41- import org .apache .paimon .shade .caffeine2 .com .github .benmanes .caffeine .cache .Caffeine ;
42- import org .apache .paimon .shade .caffeine2 .com .github .benmanes .caffeine .cache .Scheduler ;
4335
4436import org .slf4j .Logger ;
4537import org .slf4j .LoggerFactory ;
4941import java .nio .file .FileAlreadyExistsException ;
5042import java .util .Collections ;
5143import java .util .List ;
52- import java .util .concurrent .Executors ;
53- import java .util .concurrent .TimeUnit ;
5444
5545import static org .apache .paimon .CoreOptions .TYPE ;
5646import static org .apache .paimon .TableType .OBJECT_TABLE ;
57- import static org .apache .paimon .options .CatalogOptions .FILE_IO_ALLOW_CACHE ;
58- import static org .apache .paimon .rest .RESTApi .TOKEN_EXPIRATION_SAFE_TIME_MILLIS ;
5947
6048/** Wrap over RESTCatalog to provide basic operations for virtual path. */
6149public class VFSOperations {
50+
6251 private static final Logger LOG = LoggerFactory .getLogger (VFSOperations .class );
6352
6453 private final RESTApi api ;
6554 private final CatalogContext context ;
6655
67- // table id -> fileIO
68- private static final Cache <VFSDataToken , FileIO > FILE_IO_CACHE =
69- Caffeine .newBuilder ()
70- .expireAfterAccess (30 , TimeUnit .MINUTES )
71- .maximumSize (1000 )
72- .removalListener (
73- (ignored , value , cause ) -> IOUtils .closeQuietly ((FileIO ) value ))
74- .scheduler (
75- Scheduler .forScheduledExecutorService (
76- Executors .newSingleThreadScheduledExecutor (
77- ThreadUtils .newDaemonThreadFactory (
78- "rest-token-file-io-scheduler" ))))
79- .build ();
80-
81- private static final Cache <String , VFSDataToken > TOKEN_CACHE =
82- Caffeine .newBuilder ().expireAfterAccess (30 , TimeUnit .MINUTES ).maximumSize (1000 ).build ();
83-
8456 public VFSOperations (CatalogContext context ) {
8557 this .context = context ;
8658 this .api = new RESTApi (context .options ());
@@ -116,9 +88,7 @@ public VFSIdentifier getVFSIdentifier(String virtualPath) throws IOException {
11688 }
11789 // Get real path
11890 StringBuilder realPath = new StringBuilder (table .getPath ());
119- boolean isTableRoot = true ;
12091 if (parts .length > 2 ) {
121- isTableRoot = false ;
12292 if (!table .getPath ().endsWith ("/" )) {
12393 realPath .append ("/" );
12494 }
@@ -129,9 +99,8 @@ public VFSIdentifier getVFSIdentifier(String virtualPath) throws IOException {
12999 }
130100 }
131101 }
132- // Get REST token
133- FileIO fileIO = getFileIO (new Identifier (databaseName , tableName ), table );
134102
103+ FileIO fileIO = new RESTTokenFileIO (context , api , identifier , new Path (table .getPath ()));
135104 if (parts .length == 2 ) {
136105 return new VFSTableRootIdentifier (
137106 table , realPath .toString (), fileIO , databaseName , tableName );
@@ -254,66 +223,6 @@ private void tryCreateObjectTable(Identifier identifier, Schema schema) throws I
254223 }
255224 }
256225
257- private FileIO getFileIO (Identifier identifier , GetTableResponse table ) throws IOException {
258- VFSDataToken token = TOKEN_CACHE .getIfPresent (table .getId ());
259- if (shouldRefresh (token )) {
260- synchronized (TOKEN_CACHE ) {
261- token = TOKEN_CACHE .getIfPresent (table .getId ());
262- if (shouldRefresh (token )) {
263- token = refreshToken (identifier );
264- TOKEN_CACHE .put (table .getId (), token );
265- }
266- }
267- }
268-
269- FileIO fileIO = FILE_IO_CACHE .getIfPresent (token );
270- if (fileIO != null ) {
271- return fileIO ;
272- }
273-
274- synchronized (FILE_IO_CACHE ) {
275- fileIO = FILE_IO_CACHE .getIfPresent (token );
276- if (fileIO != null ) {
277- return fileIO ;
278- }
279-
280- Options options = context .options ();
281- // the original options are not overwritten
282- options = new Options (RESTUtil .merge (token .token (), options .toMap ()));
283- options .set (FILE_IO_ALLOW_CACHE , false );
284- CatalogContext fileIOContext = CatalogContext .create (options );
285- fileIO = FileIO .get (new Path (table .getPath ()), fileIOContext );
286- FILE_IO_CACHE .put (token , fileIO );
287- return fileIO ;
288- }
289- }
290-
291- private boolean shouldRefresh (VFSDataToken token ) {
292- return token == null
293- || token .expireAtMillis () - System .currentTimeMillis ()
294- < TOKEN_EXPIRATION_SAFE_TIME_MILLIS ;
295- }
296-
297- private VFSDataToken refreshToken (Identifier identifier ) throws IOException {
298- LOG .info ("begin refresh data token for identifier [{}]" , identifier );
299- GetTableTokenResponse response ;
300- try {
301- response = api .loadTableToken (identifier );
302- } catch (NoSuchResourceException e ) {
303- throw new FileNotFoundException ("Table " + identifier + " not found" );
304- } catch (ForbiddenException e ) {
305- throw new IOException ("No permission to access table " + identifier );
306- }
307-
308- LOG .info (
309- "end refresh data token for identifier [{}] expiresAtMillis [{}]" ,
310- identifier ,
311- response .getExpiresAtMillis ());
312-
313- VFSDataToken token = new VFSDataToken (response .getToken (), response .getExpiresAtMillis ());
314- return token ;
315- }
316-
317226 private GetTableResponse loadTableMetadata (Identifier identifier ) throws IOException {
318227 // if the table is system table, we need to load table metadata from the system table's data
319228 // table
0 commit comments