1616import com .google .common .annotations .VisibleForTesting ;
1717import com .google .common .cache .Cache ;
1818import com .google .common .util .concurrent .UncheckedExecutionException ;
19- import io .airlift .units .DataSize ;
20- import io .trino .collect .cache .EvictableCacheBuilder ;
2119import io .trino .plugin .hive .metastore .Partition ;
2220import io .trino .plugin .hive .metastore .Storage ;
2321import io .trino .plugin .hive .metastore .Table ;
4038import static com .google .common .base .Preconditions .checkState ;
4139import static com .google .common .base .Throwables .throwIfInstanceOf ;
4240import static com .google .common .base .Throwables .throwIfUnchecked ;
41+ import static com .google .common .collect .ImmutableList .toImmutableList ;
4342import static io .airlift .slice .SizeOf .instanceSize ;
4443import static io .airlift .slice .SizeOf .sizeOfObjectArray ;
45- import static java . lang . Math . toIntExact ;
44+ import static io . trino . plugin . hive . fs . DirectoryListingCacheKey . allKeysWithPath ;
4645import static java .util .Collections .synchronizedList ;
4746import static java .util .Objects .requireNonNull ;
4847
5554public class TransactionScopeCachingDirectoryLister
5655 implements DirectoryLister
5756{
57+ private final long transactionId ;
5858 //TODO use a cache key based on Path & SchemaTableName and iterate over the cache keys
5959 // to deal more efficiently with cache invalidation scenarios for partitioned tables.
60- private final Cache <DirectoryListingCacheKey , FetchingValueHolder > cache ;
60+ private final Cache <TransactionDirectoryListingCacheKey , FetchingValueHolder > cache ;
6161 private final DirectoryLister delegate ;
6262
63- public TransactionScopeCachingDirectoryLister (DirectoryLister delegate , DataSize maxSize )
63+ public TransactionScopeCachingDirectoryLister (DirectoryLister delegate , long transactionId , Cache < TransactionDirectoryListingCacheKey , FetchingValueHolder > cache )
6464 {
65- this (delegate , maxSize , Optional .empty ());
66- }
67-
68- @ VisibleForTesting
69- TransactionScopeCachingDirectoryLister (DirectoryLister delegate , DataSize maxSize , Optional <Integer > concurrencyLevel )
70- {
71- EvictableCacheBuilder <DirectoryListingCacheKey , FetchingValueHolder > cacheBuilder = EvictableCacheBuilder .newBuilder ()
72- .maximumWeight (maxSize .toBytes ())
73- .weigher ((key , value ) -> toIntExact (key .getRetainedSizeInBytes () + value .getRetainedSizeInBytes ()));
74- concurrencyLevel .ifPresent (cacheBuilder ::concurrencyLevel );
75- this .cache = cacheBuilder .build ();
7665 this .delegate = requireNonNull (delegate , "delegate is null" );
66+ this .transactionId = transactionId ;
67+ this .cache = requireNonNull (cache , "cache is null" );
7768 }
7869
7970 @ Override
8071 public RemoteIterator <TrinoFileStatus > list (FileSystem fs , Table table , Path path )
8172 throws IOException
8273 {
83- return listInternal (fs , table , new DirectoryListingCacheKey (path .toString (), false ));
74+ return listInternal (fs , table , new TransactionDirectoryListingCacheKey ( transactionId , new DirectoryListingCacheKey (path .toString (), false ) ));
8475 }
8576
8677 @ Override
8778 public RemoteIterator <TrinoFileStatus > listFilesRecursively (FileSystem fs , Table table , Path path )
8879 throws IOException
8980 {
90- return listInternal (fs , table , new DirectoryListingCacheKey (path .toString (), true ));
81+ return listInternal (fs , table , new TransactionDirectoryListingCacheKey ( transactionId , new DirectoryListingCacheKey (path .toString (), true ) ));
9182 }
9283
93- private RemoteIterator <TrinoFileStatus > listInternal (FileSystem fs , Table table , DirectoryListingCacheKey cacheKey )
84+ private RemoteIterator <TrinoFileStatus > listInternal (FileSystem fs , Table table , TransactionDirectoryListingCacheKey cacheKey )
9485 throws IOException
9586 {
9687 FetchingValueHolder cachedValueHolder ;
@@ -101,7 +92,7 @@ private RemoteIterator<TrinoFileStatus> listInternal(FileSystem fs, Table table,
10192 Throwable throwable = e .getCause ();
10293 throwIfInstanceOf (throwable , IOException .class );
10394 throwIfUnchecked (throwable );
104- throw new RuntimeException ("Failed to list directory: " + cacheKey .getPath (), throwable );
95+ throw new RuntimeException ("Failed to list directory: " + cacheKey .getKey (). getPath (), throwable );
10596 }
10697
10798 if (cachedValueHolder .isFullyCached ()) {
@@ -111,21 +102,23 @@ private RemoteIterator<TrinoFileStatus> listInternal(FileSystem fs, Table table,
111102 return cachingRemoteIterator (cachedValueHolder , cacheKey );
112103 }
113104
114- private RemoteIterator <TrinoFileStatus > createListingRemoteIterator (FileSystem fs , Table table , DirectoryListingCacheKey cacheKey )
105+ private RemoteIterator <TrinoFileStatus > createListingRemoteIterator (FileSystem fs , Table table , TransactionDirectoryListingCacheKey cacheKey )
115106 throws IOException
116107 {
117- if (cacheKey .isRecursiveFilesOnly ()) {
118- return delegate .listFilesRecursively (fs , table , new Path (cacheKey .getPath ()));
108+ if (cacheKey .getKey (). isRecursiveFilesOnly ()) {
109+ return delegate .listFilesRecursively (fs , table , new Path (cacheKey .getKey (). getPath ()));
119110 }
120- return delegate .list (fs , table , new Path (cacheKey .getPath ()));
111+ return delegate .list (fs , table , new Path (cacheKey .getKey (). getPath ()));
121112 }
122113
123114 @ Override
124115 public void invalidate (Table table )
125116 {
126117 if (isLocationPresent (table .getStorage ())) {
127118 if (table .getPartitionColumns ().isEmpty ()) {
128- cache .invalidateAll (DirectoryListingCacheKey .allKeysWithPath (new Path (table .getStorage ().getLocation ())));
119+ cache .invalidateAll (allKeysWithPath (new Path (table .getStorage ().getLocation ())).stream ()
120+ .map (key -> new TransactionDirectoryListingCacheKey (transactionId , key ))
121+ .collect (toImmutableList ()));
129122 }
130123 else {
131124 // a partitioned table can have multiple paths in cache
@@ -139,12 +132,14 @@ public void invalidate(Table table)
139132 public void invalidate (Partition partition )
140133 {
141134 if (isLocationPresent (partition .getStorage ())) {
142- cache .invalidateAll (DirectoryListingCacheKey .allKeysWithPath (new Path (partition .getStorage ().getLocation ())));
135+ cache .invalidateAll (allKeysWithPath (new Path (partition .getStorage ().getLocation ())).stream ()
136+ .map (key -> new TransactionDirectoryListingCacheKey (transactionId , key ))
137+ .collect (toImmutableList ()));
143138 }
144139 delegate .invalidate (partition );
145140 }
146141
147- private RemoteIterator <TrinoFileStatus > cachingRemoteIterator (FetchingValueHolder cachedValueHolder , DirectoryListingCacheKey cacheKey )
142+ private RemoteIterator <TrinoFileStatus > cachingRemoteIterator (FetchingValueHolder cachedValueHolder , TransactionDirectoryListingCacheKey cacheKey )
148143 {
149144 return new RemoteIterator <>()
150145 {
@@ -183,11 +178,11 @@ public TrinoFileStatus next()
183178 @ VisibleForTesting
184179 boolean isCached (Path path )
185180 {
186- return isCached (new DirectoryListingCacheKey (path .toString (), false ));
181+ return isCached (new TransactionDirectoryListingCacheKey ( transactionId , new DirectoryListingCacheKey (path .toString (), false ) ));
187182 }
188183
189184 @ VisibleForTesting
190- boolean isCached (DirectoryListingCacheKey cacheKey )
185+ boolean isCached (TransactionDirectoryListingCacheKey cacheKey )
191186 {
192187 FetchingValueHolder cached = cache .getIfPresent (cacheKey );
193188 return cached != null && cached .isFullyCached ();
@@ -199,7 +194,7 @@ private static boolean isLocationPresent(Storage storage)
199194 return storage .getOptionalLocation ().isPresent () && !storage .getLocation ().isEmpty ();
200195 }
201196
202- private static class FetchingValueHolder
197+ static class FetchingValueHolder
203198 {
204199 private static final long ATOMIC_LONG_SIZE = instanceSize (AtomicLong .class );
205200 private static final long INSTANCE_SIZE = instanceSize (FetchingValueHolder .class );
0 commit comments