UnpackedObjectCache.java

  1. /*
  2.  * Copyright (C) 2010, Google Inc.
  3.  * and other copyright owners as documented in the project's IP log.
  4.  *
  5.  * This program and the accompanying materials are made available
  6.  * under the terms of the Eclipse Distribution License v1.0 which
  7.  * accompanies this distribution, is reproduced below, and is
  8.  * available at http://www.eclipse.org/org/documents/edl-v10.php
  9.  *
  10.  * All rights reserved.
  11.  *
  12.  * Redistribution and use in source and binary forms, with or
  13.  * without modification, are permitted provided that the following
  14.  * conditions are met:
  15.  *
  16.  * - Redistributions of source code must retain the above copyright
  17.  *   notice, this list of conditions and the following disclaimer.
  18.  *
  19.  * - Redistributions in binary form must reproduce the above
  20.  *   copyright notice, this list of conditions and the following
  21.  *   disclaimer in the documentation and/or other materials provided
  22.  *   with the distribution.
  23.  *
  24.  * - Neither the name of the Eclipse Foundation, Inc. nor the
  25.  *   names of its contributors may be used to endorse or promote
  26.  *   products derived from this software without specific prior
  27.  *   written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  */

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

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

  45. import org.eclipse.jgit.lib.AnyObjectId;
  46. import org.eclipse.jgit.lib.ObjectId;

  47. /** Remembers objects that are currently unpacked. */
  48. class UnpackedObjectCache {
  49.     private static final int INITIAL_BITS = 5; // size = 32

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

  51.     private volatile Table table;

  52.     UnpackedObjectCache() {
  53.         table = new Table(INITIAL_BITS);
  54.     }

  55.     boolean isUnpacked(AnyObjectId objectId) {
  56.         return table.contains(objectId);
  57.     }

  58.     void add(AnyObjectId objectId) {
  59.         Table t = table;
  60.         if (t.add(objectId)) {
  61.             // The object either already exists in the table, or was
  62.             // successfully added. Either way leave the table alone.
  63.             //
  64.         } else {
  65.             // The object won't fit into the table. Implement a crude
  66.             // cache removal by just dropping the table away, but double
  67.             // it in size for the next incarnation.
  68.             //
  69.             Table n = new Table(Math.min(t.bits + 1, MAX_BITS));
  70.             n.add(objectId);
  71.             table = n;
  72.         }
  73.     }

  74.     void remove(AnyObjectId objectId) {
  75.         if (isUnpacked(objectId))
  76.             clear();
  77.     }

  78.     void clear() {
  79.         table = new Table(INITIAL_BITS);
  80.     }

  81.     private static class Table {
  82.         private static final int MAX_CHAIN = 8;

  83.         private final AtomicReferenceArray<ObjectId> ids;

  84.         private final int shift;

  85.         final int bits;

  86.         Table(int bits) {
  87.             this.ids = new AtomicReferenceArray<>(1 << bits);
  88.             this.shift = 32 - bits;
  89.             this.bits = bits;
  90.         }

  91.         boolean contains(AnyObjectId toFind) {
  92.             int i = index(toFind);
  93.             for (int n = 0; n < MAX_CHAIN; n++) {
  94.                 ObjectId obj = ids.get(i);
  95.                 if (obj == null)
  96.                     break;

  97.                 if (AnyObjectId.equals(obj, toFind))
  98.                     return true;

  99.                 if (++i == ids.length())
  100.                     i = 0;
  101.             }
  102.             return false;
  103.         }

  104.         boolean add(AnyObjectId toAdd) {
  105.             int i = index(toAdd);
  106.             for (int n = 0; n < MAX_CHAIN;) {
  107.                 ObjectId obj = ids.get(i);
  108.                 if (obj == null) {
  109.                     if (ids.compareAndSet(i, null, toAdd.copy()))
  110.                         return true;
  111.                     else
  112.                         continue;
  113.                 }

  114.                 if (AnyObjectId.equals(obj, toAdd))
  115.                     return true;

  116.                 if (++i == ids.length())
  117.                     i = 0;
  118.                 n++;
  119.             }
  120.             return false;
  121.         }

  122.         private int index(AnyObjectId id) {
  123.             return id.hashCode() >>> shift;
  124.         }
  125.     }
  126. }