@@ -38,7 +38,6 @@ import (
3838 "runtime"
3939 "slices"
4040 "strings"
41- "sync"
4241 "time"
4342
4443 "github.com/hashicorp/go-retryablehttp"
@@ -63,7 +62,7 @@ import (
6362// This is terrible but simpler than plumbing around a cache for now.
6463// We just hold the expanded APK in memory rather than re-parsing it every time,
6564// which is expensive. This also dedupes simultaneous fetches.
66- var globalApkCache = & apkCache {}
65+ var globalApkCache = newFlightCache [ string , * expandapk. APKExpanded ]()
6766
6867type APK struct {
6968 arch string
@@ -1260,42 +1259,6 @@ func (a *APK) cachedPackage(ctx context.Context, pkg InstallablePackage, cacheDi
12601259 return & exp , nil
12611260}
12621261
1263- type apkResult struct {
1264- exp * expandapk.APKExpanded
1265- err error
1266- }
1267-
1268- type apkCache struct {
1269- // url -> func() apkResult (from sync.OnceValue(...))
1270- onces sync.Map
1271- }
1272-
1273- func (c * apkCache ) get (ctx context.Context , a * APK , pkg InstallablePackage ) (* expandapk.APKExpanded , error ) {
1274- u := pkg .URL ()
1275- // Do all the expensive things inside sync.OnceValue()
1276- fn := func () apkResult {
1277- exp , err := expandPackage (ctx , a , pkg )
1278- return apkResult {
1279- exp : exp ,
1280- err : err ,
1281- }
1282- }
1283- once , cached := c .onces .LoadOrStore (u , sync .OnceValue (fn ))
1284- result := once .(func () apkResult )()
1285- if cached && result .exp != nil {
1286- // If we find a value in the cache, we should check to make sure the tar file it references still exists.
1287- // If it references a non-existent file, we should act as though this was a cache miss and expand the
1288- // APK again.
1289- if ! result .exp .IsValid () {
1290- newValue := sync .OnceValue (fn )
1291- c .onces .Store (u , newValue )
1292- result = newValue ()
1293- }
1294- }
1295-
1296- return result .exp , result .err
1297- }
1298-
12991262func (a * APK ) expandPackage (ctx context.Context , pkg InstallablePackage ) (* expandapk.APKExpanded , error ) {
13001263 if a .cache == nil {
13011264 // If we don't have a cache configured, don't use the global cache.
@@ -1305,7 +1268,26 @@ func (a *APK) expandPackage(ctx context.Context, pkg InstallablePackage) (*expan
13051268 return expandPackage (ctx , a , pkg )
13061269 }
13071270
1308- return globalApkCache .get (ctx , a , pkg )
1271+ cached := true
1272+ val , err := globalApkCache .Do (pkg .URL (), func () (* expandapk.APKExpanded , error ) {
1273+ cached = false
1274+ return expandPackage (ctx , a , pkg )
1275+ })
1276+ if ! cached {
1277+ // We've just executed the callback - either successfully cached or
1278+ // failed (errors aren't cached). Either way, no validation needed.
1279+ return val , err
1280+ }
1281+ if val != nil {
1282+ // If we find a value in the cache, we should check to make sure the tar file it references still exists.
1283+ // If it references a non-existent file, we should act as though this was a cache miss and expand the
1284+ // APK again.
1285+ if ! val .IsValid () {
1286+ globalApkCache .Forget (pkg .URL ())
1287+ return a .expandPackage (ctx , pkg )
1288+ }
1289+ }
1290+ return val , err
13091291}
13101292
13111293func expandPackage (ctx context.Context , a * APK , pkg InstallablePackage ) (* expandapk.APKExpanded , error ) {
0 commit comments