UnpackedObjectCache.java

  1. /*
  2.  * Copyright (C) 2010, Google Inc. and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */

  10. package org.eclipse.jgit.internal.storage.file;

  11. import java.util.concurrent.atomic.AtomicReferenceArray;

  12. import org.eclipse.jgit.lib.AnyObjectId;
  13. import org.eclipse.jgit.lib.ObjectId;

  14. /** Remembers objects that are currently unpacked. */
  15. class UnpackedObjectCache {
  16.     private static final int INITIAL_BITS = 5; // size = 32

  17.     private static final int MAX_BITS = 11; // size = 2048

  18.     private volatile Table table;

  19.     UnpackedObjectCache() {
  20.         table = new Table(INITIAL_BITS);
  21.     }

  22.     boolean isUnpacked(AnyObjectId objectId) {
  23.         return table.contains(objectId);
  24.     }

  25.     void add(AnyObjectId objectId) {
  26.         Table t = table;
  27.         if (t.add(objectId)) {
  28.             // The object either already exists in the table, or was
  29.             // successfully added. Either way leave the table alone.
  30.             //
  31.         } else {
  32.             // The object won't fit into the table. Implement a crude
  33.             // cache removal by just dropping the table away, but double
  34.             // it in size for the next incarnation.
  35.             //
  36.             Table n = new Table(Math.min(t.bits + 1, MAX_BITS));
  37.             n.add(objectId);
  38.             table = n;
  39.         }
  40.     }

  41.     void remove(AnyObjectId objectId) {
  42.         if (isUnpacked(objectId))
  43.             clear();
  44.     }

  45.     void clear() {
  46.         table = new Table(INITIAL_BITS);
  47.     }

  48.     private static class Table {
  49.         private static final int MAX_CHAIN = 8;

  50.         private final AtomicReferenceArray<ObjectId> ids;

  51.         private final int shift;

  52.         final int bits;

  53.         Table(int bits) {
  54.             this.ids = new AtomicReferenceArray<>(1 << bits);
  55.             this.shift = 32 - bits;
  56.             this.bits = bits;
  57.         }

  58.         boolean contains(AnyObjectId toFind) {
  59.             int i = index(toFind);
  60.             for (int n = 0; n < MAX_CHAIN; n++) {
  61.                 ObjectId obj = ids.get(i);
  62.                 if (obj == null)
  63.                     break;

  64.                 if (AnyObjectId.isEqual(obj, toFind))
  65.                     return true;

  66.                 if (++i == ids.length())
  67.                     i = 0;
  68.             }
  69.             return false;
  70.         }

  71.         boolean add(AnyObjectId toAdd) {
  72.             int i = index(toAdd);
  73.             for (int n = 0; n < MAX_CHAIN;) {
  74.                 ObjectId obj = ids.get(i);
  75.                 if (obj == null) {
  76.                     if (ids.compareAndSet(i, null, toAdd.copy())) {
  77.                         return true;
  78.                     }
  79.                     continue;
  80.                 }

  81.                 if (AnyObjectId.isEqual(obj, toAdd)) {
  82.                     return true;
  83.                 }

  84.                 if (++i == ids.length()) {
  85.                     i = 0;
  86.                 }
  87.                 n++;
  88.             }
  89.             return false;
  90.         }

  91.         private int index(AnyObjectId id) {
  92.             return id.hashCode() >>> shift;
  93.         }
  94.     }
  95. }