class ParseKeyValueCache {

  static void saveToKeyValueCache(String key, String value) {
    synchronized (MUTEX_IO) {
      File prior = getKeyValueCacheFile(key);
      if (prior != null) {
        prior.delete();
      }
      File f = createKeyValueCacheFile(key);
      try {
        ParseFileUtils.writeByteArrayToFile(f, value.getBytes("UTF-8"));
      } catch (IOException e) {
        // do nothing
      }

      // Check if we should kick out old cache entries
      File[] files = getKeyValueCacheDir().listFiles();
      // We still need this check since dir.mkdir() may fail
      if (files == null || files.length == 0) {
        return;
      }

      int numFiles = files.length;
      int numBytes = 0;
      for (File file : files) {
        numBytes += file.length();
      }

      // If we do not need to clear the cache, simply return
      if (numFiles <= maxKeyValueCacheFiles && numBytes <= maxKeyValueCacheBytes) {
        return;
      }

      // We need to kick out some cache entries.
      // Sort oldest-first. We touch on read so mtime is really LRU.
      // Sometimes (i.e. tests) the time of lastModified isn't granular enough,
      // so we resort
      // to sorting by the file name which is always prepended with time in ms
      Arrays.sort(files, new Comparator<File>() {
        @Override
        public int compare(File f1, File f2) {
          int dateCompare = Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
          if (dateCompare != 0) {
            return dateCompare;
          } else {
            return f1.getName().compareTo(f2.getName());
          }
        }
      });

      for (File file : files) {
        numFiles--;
        numBytes -= file.length();
        file.delete();

        if (numFiles <= maxKeyValueCacheFiles && numBytes <= maxKeyValueCacheBytes) {
          break;
        }
      }
    }
  }

}