private static void addToCache(
     PersistentHashMap<String, Set<String>> cache, String key, String value) throws IOException {
   Set<String> values = cache.get(key);
   if (values == null) values = new THashSet<String>();
   values.add(value);
   cache.put(key, values);
 }
 public Set<String> read(DataInput s) throws IOException {
   int count = s.readInt();
   Set<String> result = new THashSet<String>(count);
   while (count-- > 0) {
     result.add(s.readUTF());
   }
   return result;
 }
 public void save(DataOutput s, Set<String> set) throws IOException {
   s.writeInt(set.size());
   for (String each : set) {
     s.writeUTF(each);
   }
 }
    private static void removeStaleJarFilesIfNeeded(
        File snapshotInfoFile, PersistentHashMap<String, CacheLibraryInfo> info)
        throws IOException {
      File versionFile = getVersionFile(snapshotInfoFile);
      long lastModified = versionFile.lastModified();
      if ((System.currentTimeMillis() - lastModified) < 30 * 24 * 60 * 60 * 1000L) {
        return;
      }

      // snapshotInfo is persistent mapping of project library path -> jar snapshot path
      // Stale jars are the jars that do not exist with registered paths, to remove them:
      // - Take all snapshot library files in jar directory
      // - Collect librarySnapshot -> projectLibraryPaths and existing projectLibraryPath ->
      // librarySnapshot
      // - Remove all projectLibraryPaths that doesn't exist from persistent mapping
      // - Remove jar library snapshots that have no projectLibraryPath
      Set<String> availableLibrarySnapshots =
          new THashSet<String>(
              Arrays.asList(
                  snapshotInfoFile
                      .getParentFile()
                      .list(
                          new FilenameFilter() {
                            @Override
                            public boolean accept(File dir, String name) {
                              int lastDotPosition = name.lastIndexOf('.');
                              if (lastDotPosition == -1) return false;
                              String extension = name.substring(lastDotPosition + 1);
                              if (extension.length() != 40 || !consistsOfHexLetters(extension))
                                return false;
                              return true;
                            }

                            private boolean consistsOfHexLetters(String extension) {
                              for (int i = 0; i < extension.length(); ++i) {
                                if (Character.digit(extension.charAt(i), 16) == -1) return false;
                              }
                              return true;
                            }
                          })));

      final List<String> invalidLibraryFilePaths = ContainerUtil.newArrayList();
      final List<String> allLibraryFilePaths = ContainerUtil.newArrayList();
      MultiMap<String, String> jarSnapshotFileToLibraryFilePaths = new MultiMap<String, String>();
      Set<String> validLibraryFilePathToJarSnapshotFilePaths = ContainerUtil.newTroveSet();

      info.processKeys(new CommonProcessors.CollectProcessor<String>(allLibraryFilePaths));
      for (String filePath : allLibraryFilePaths) {
        CacheLibraryInfo libraryInfo = info.get(filePath);
        if (libraryInfo == null) continue;

        jarSnapshotFileToLibraryFilePaths.putValue(libraryInfo.mySnapshotPath, filePath);
        if (new File(filePath).exists()) {
          validLibraryFilePathToJarSnapshotFilePaths.add(filePath);
        } else {
          invalidLibraryFilePaths.add(filePath);
        }
      }

      for (String invalidLibraryFilePath : invalidLibraryFilePaths) {
        LOG.info("removing stale library reference:" + invalidLibraryFilePath);
        info.remove(invalidLibraryFilePath);
      }
      for (Map.Entry<String, Collection<String>> e : jarSnapshotFileToLibraryFilePaths.entrySet()) {
        for (String libraryFilePath : e.getValue()) {
          if (validLibraryFilePathToJarSnapshotFilePaths.contains(libraryFilePath)) {
            availableLibrarySnapshots.remove(e.getKey());
            break;
          }
        }
      }
      for (String availableLibrarySnapshot : availableLibrarySnapshots) {
        File librarySnapshotFileToDelete =
            new File(snapshotInfoFile.getParentFile(), availableLibrarySnapshot);
        LOG.info("removing stale library snapshot:" + librarySnapshotFileToDelete);
        FileUtil.delete(librarySnapshotFileToDelete);
      }

      saveVersion(
          versionFile); // time stamp will change to start another time interval when stale jar
      // files are tracked
    }