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 44 package org.eclipse.jgit.internal.storage.file; 45 46 import java.util.concurrent.atomic.AtomicReferenceArray; 47 48 import org.eclipse.jgit.lib.AnyObjectId; 49 import org.eclipse.jgit.lib.ObjectId; 50 51 /** Remembers objects that are currently unpacked. */ 52 class UnpackedObjectCache { 53 private static final int INITIAL_BITS = 5; // size = 32 54 55 private static final int MAX_BITS = 11; // size = 2048 56 57 private volatile Table table; 58 59 UnpackedObjectCache() { 60 table = new Table(INITIAL_BITS); 61 } 62 63 boolean isUnpacked(AnyObjectId objectId) { 64 return table.contains(objectId); 65 } 66 67 void add(AnyObjectId objectId) { 68 Table t = table; 69 if (t.add(objectId)) { 70 // The object either already exists in the table, or was 71 // successfully added. Either way leave the table alone. 72 // 73 } else { 74 // The object won't fit into the table. Implement a crude 75 // cache removal by just dropping the table away, but double 76 // it in size for the next incarnation. 77 // 78 Table n = new Table(Math.min(t.bits + 1, MAX_BITS)); 79 n.add(objectId); 80 table = n; 81 } 82 } 83 84 void remove(AnyObjectId objectId) { 85 if (isUnpacked(objectId)) 86 clear(); 87 } 88 89 void clear() { 90 table = new Table(INITIAL_BITS); 91 } 92 93 private static class Table { 94 private static final int MAX_CHAIN = 8; 95 96 private final AtomicReferenceArray<ObjectId> ids; 97 98 private final int shift; 99 100 final int bits; 101 102 Table(int bits) { 103 this.ids = new AtomicReferenceArray<>(1 << bits); 104 this.shift = 32 - bits; 105 this.bits = bits; 106 } 107 108 boolean contains(AnyObjectId toFind) { 109 int i = index(toFind); 110 for (int n = 0; n < MAX_CHAIN; n++) { 111 ObjectId obj = ids.get(i); 112 if (obj == null) 113 break; 114 115 if (AnyObjectId.equals(obj, toFind)) 116 return true; 117 118 if (++i == ids.length()) 119 i = 0; 120 } 121 return false; 122 } 123 124 boolean add(AnyObjectId toAdd) { 125 int i = index(toAdd); 126 for (int n = 0; n < MAX_CHAIN;) { 127 ObjectId obj = ids.get(i); 128 if (obj == null) { 129 if (ids.compareAndSet(i, null, toAdd.copy())) 130 return true; 131 else 132 continue; 133 } 134 135 if (AnyObjectId.equals(obj, toAdd)) 136 return true; 137 138 if (++i == ids.length()) 139 i = 0; 140 n++; 141 } 142 return false; 143 } 144 145 private int index(AnyObjectId id) { 146 return id.hashCode() >>> shift; 147 } 148 } 149 }