Search Unity

Removing all old versions of a bundle when building/updating

Discussion in 'Addressables' started by shomz, May 14, 2020.

  1. shomz

    shomz

    Joined:
    Nov 9, 2016
    Posts:
    16
    There should be a feature to let us keep only the latest versions of bundles when overwriting or updating builds. Removing the whole build cache and the re-adding all bundles seems to be the only solution for now.

    This should be the case both when building data and also when downloading data.

    Not using hashes helps when building, but it still poses a problem when downloading, because the bundles get extracted in a form of *bundleName/bundleHash/* so it will preserve previous *bundleHash* subdirs.

    Any chance we can get this with the next version?
     
  2. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    Would be great, yes! I tried
     Caching.ClearAllCachedVersions(identifier);
    and
    Addressables.ClearDependencyCacheAsync(identifier);
    and neither worked in my unit tests :) I had to
    Caching.ClearCache();
    everything.
     
  3. LilMako17

    LilMako17

    Joined:
    Apr 10, 2019
    Posts:
    43
    Here's my current code to solve this problem on android. haven't tested it on IOS yet. It feels pretty hacky, i wish there was a cleaner solution too. This code assumes your bundle names don't change and that you have "Append hash to filename" turned on for all your bundles.
    Code (CSharp):
    1.     private void ClearOldData()
    2.     {
    3.         Log.Debug("Caches before");
    4.         DebugUtility.PrintCacheSizes();
    5.         var bundleNames = new HashSet<string>();
    6.         var bundles = new HashSet<CachedAssetBundle>();
    7.         foreach (var loc in Addressables.ResourceLocators)
    8.         {
    9.             foreach (var key in loc.Keys)
    10.             {
    11.                 if (loc.Locate(key, typeof(object), out var resourceLocations))
    12.                 {
    13.                     foreach (var l in resourceLocations)
    14.                     {
    15.                         if (l.HasDependencies)
    16.                         {
    17.                             foreach (var d in l.Dependencies)
    18.                             {
    19.                                 var bundleName = Path.GetFileName(d.InternalId);
    20.                                 if (!bundleNames.Contains(bundleName))
    21.                                 {
    22.                                     if (d.Data is AssetBundleRequestOptions dependencyBundle)
    23.                                     {
    24.                                         bundleNames.Add(bundleName);
    25.                                         bundles.Add(new CachedAssetBundle(bundleName, Hash128.Parse(dependencyBundle.Hash)));
    26.                                     }
    27.                                 }
    28.                             }
    29.                         }
    30.                     }
    31.                 }
    32.                 else
    33.                 {
    34.                     Log.Error("Failed to locate " + key);
    35.                 }
    36.             }
    37.         }
    38.  
    39.         var cache = Caching.GetCacheAt(0);
    40.         var path = cache.path;
    41.         Log.Debug("Cache Path:  " + path);
    42.  
    43.         var bundlesToRemove = new List<CachedAssetBundle>();
    44.         try
    45.         {
    46.             var folders = Directory.GetDirectories(path);
    47.             foreach (var folder in folders)
    48.             {
    49.                 var folderName = new DirectoryInfo(folder).Name;
    50.                 if (!bundles.Any(x => x.name.Contains(folderName)))
    51.                 {
    52.                     Log.Debug("Found old bundle: " + folderName);
    53.                     var hash = folderName.Split('_').Last();
    54.                     var cachBundle = new CachedAssetBundle(folderName, Hash128.Parse(hash));
    55.                     bundlesToRemove.Add(cachBundle);
    56.                 }
    57.             }
    58.         }
    59.         catch(Exception e)
    60.         {
    61. #if UNITY_EDITOR
    62.             Log.Debug("No cache directory found in Editor.");
    63. #else
    64.             Log.Error("Failed to get old bundles when trying to ClearOldData " + e.ToString());
    65. #endif
    66.         }
    67.  
    68.         foreach (var bundle in bundlesToRemove)
    69.         {
    70.             var hashes = new List<Hash128>();
    71.             var bundleName = bundle.name;
    72.             Caching.GetCachedVersions(bundleName, hashes);
    73.             if (hashes.Count > 0)
    74.             {
    75.                 var success = Caching.ClearCachedVersion(bundleName, bundle.hash);
    76.                 if (success)
    77.                 {
    78.                     Log.Debug("Cleared old bundle " + bundleName);
    79.                 }
    80.                 else
    81.                 {
    82.                     Log.Warn("failed to delete bundle " + bundleName);
    83.                 }
    84.             }
    85.             else
    86.             {
    87.                 Debug.Log("bundle " + bundleName + " " + bundle.hash + " found no cached versions");
    88.             }
    89.         }
    90.  
    91.         Log.Debug("Caches after");
    92.         DebugUtility.PrintCacheSizes();
    93.     }
     
  4. EmilieCollard191

    EmilieCollard191

    Joined:
    May 8, 2019
    Posts:
    77
    Edit: The following code is obsolete. You can set clear cache behavior to Clear when new version is loaded

    @LilMako17 solution seem to not work anymore or dont work with my setting.

    So here my updated code.

    We take all our addressable location add their hash to a list.
    After we iterate on all the sub folder in the cache.
    If the sub folder is not in our hash list we delete it

    Code (CSharp):
    1. static void ClearOldData()
    2.         {
    3.             var bundlesHash = new HashSet<string>();
    4.             foreach (var loc in Addressables.ResourceLocators)
    5.             {
    6.                 foreach (var key in loc.Keys)
    7.                 {
    8.                     if (!loc.Locate(key, typeof(object), out var resourceLocations))
    9.                         continue;
    10.  
    11.                     foreach (var d in resourceLocations.Where(l => l.HasDependencies).SelectMany(l => l.Dependencies))
    12.                     {
    13.                         if (d.Data is AssetBundleRequestOptions dependencyBundle)
    14.                             bundlesHash.Add(dependencyBundle.Hash);
    15.                     }
    16.                 }
    17.             }
    18.  
    19.             var path = Caching.GetCacheAt(0).path;
    20.             if (!Directory.Exists(path))
    21.                 return;
    22.             foreach (var directory in Directory.GetDirectories(path).SelectMany(Directory.GetDirectories))
    23.             {
    24.                 if (!bundlesHash.Contains(new DirectoryInfo(directory).Name))
    25.                     Directory.Delete(directory, true);
    26.             }
    27.         }
     
    Last edited: Nov 9, 2021
    xwin28 and eonyanov like this.