Remove System.out.println from RevWalkFilterTest
[egit/qmx.git] / org.spearce.jgit / src / org / spearce / jgit / lib / ObjectDatabase.java
blob6a9ba4ea7cd513473e225f2996e54b91edef7952
1 /*
2 * Copyright (C) 2009, Google Inc.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org.spearce.jgit.lib;
40 import java.io.IOException;
41 import java.util.Collection;
42 import java.util.concurrent.atomic.AtomicReference;
44 /**
45 * Abstraction of arbitrary object storage.
46 * <p>
47 * An object database stores one or more Git objects, indexed by their unique
48 * {@link ObjectId}. Optionally an object database can reference one or more
49 * alternates; other ObjectDatabase instances that are searched in addition to
50 * the current database.
51 * <p>
52 * Databases are usually divided into two halves: a half that is considered to
53 * be fast to search, and a half that is considered to be slow to search. When
54 * alternates are present the fast half is fully searched (recursively through
55 * all alternates) before the slow half is considered.
57 public abstract class ObjectDatabase {
58 /** Constant indicating no alternate databases exist. */
59 protected static final ObjectDatabase[] NO_ALTERNATES = {};
61 private final AtomicReference<ObjectDatabase[]> alternates;
63 /** Initialize a new database instance for access. */
64 protected ObjectDatabase() {
65 alternates = new AtomicReference<ObjectDatabase[]>();
68 /**
69 * Does this database exist yet?
71 * @return true if this database is already created; false if the caller
72 * should invoke {@link #create()} to create this database location.
74 public boolean exists() {
75 return true;
78 /**
79 * Initialize a new object database at this location.
81 * @throws IOException
82 * the database could not be created.
84 public void create() throws IOException {
85 // Assume no action is required.
88 /**
89 * Close any resources held by this database and its active alternates.
91 public final void close() {
92 closeSelf();
93 closeAlternates();
96 /**
97 * Close any resources held by this database only; ignoring alternates.
98 * <p>
99 * To fully close this database and its referenced alternates, the caller
100 * should instead invoke {@link #close()}.
102 public void closeSelf() {
103 // Assume no action is required.
106 /** Fully close all loaded alternates and clear the alternate list. */
107 public final void closeAlternates() {
108 ObjectDatabase[] alt = alternates.get();
109 if (alt != null) {
110 alternates.set(null);
111 for (final ObjectDatabase d : alt) {
112 d.close();
118 * Does the requested object exist in this database?
119 * <p>
120 * Alternates (if present) are searched automatically.
122 * @param objectId
123 * identity of the object to test for existence of.
124 * @return true if the specified object is stored in this database, or any
125 * of the alternate databases.
127 public final boolean hasObject(final AnyObjectId objectId) {
128 return hasObjectImpl1(objectId) || hasObjectImpl2(objectId.name());
131 private final boolean hasObjectImpl1(final AnyObjectId objectId) {
132 if (hasObject1(objectId)) {
133 return true;
135 for (final ObjectDatabase alt : getAlternates()) {
136 if (alt.hasObjectImpl1(objectId)) {
137 return true;
140 return tryAgain1() && hasObject1(objectId);
143 private final boolean hasObjectImpl2(final String objectId) {
144 if (hasObject2(objectId)) {
145 return true;
147 for (final ObjectDatabase alt : getAlternates()) {
148 if (alt.hasObjectImpl2(objectId)) {
149 return true;
152 return false;
156 * Fast half of {@link #hasObject(AnyObjectId)}.
158 * @param objectId
159 * identity of the object to test for existence of.
160 * @return true if the specified object is stored in this database.
162 protected abstract boolean hasObject1(AnyObjectId objectId);
165 * Slow half of {@link #hasObject(AnyObjectId)}.
167 * @param objectName
168 * identity of the object to test for existence of.
169 * @return true if the specified object is stored in this database.
171 protected boolean hasObject2(String objectName) {
172 // Assume the search took place during hasObject1.
173 return false;
177 * Open an object from this database.
178 * <p>
179 * Alternates (if present) are searched automatically.
181 * @param curs
182 * temporary working space associated with the calling thread.
183 * @param objectId
184 * identity of the object to open.
185 * @return a {@link ObjectLoader} for accessing the data of the named
186 * object, or null if the object does not exist.
187 * @throws IOException
189 public final ObjectLoader openObject(final WindowCursor curs,
190 final AnyObjectId objectId) throws IOException {
191 ObjectLoader ldr;
193 ldr = openObjectImpl1(curs, objectId);
194 if (ldr != null) {
195 return ldr;
198 ldr = openObjectImpl2(curs, objectId.name(), objectId);
199 if (ldr != null) {
200 return ldr;
202 return null;
205 private ObjectLoader openObjectImpl1(final WindowCursor curs,
206 final AnyObjectId objectId) throws IOException {
207 ObjectLoader ldr;
209 ldr = openObject1(curs, objectId);
210 if (ldr != null) {
211 return ldr;
213 for (final ObjectDatabase alt : getAlternates()) {
214 ldr = alt.openObjectImpl1(curs, objectId);
215 if (ldr != null) {
216 return ldr;
219 if (tryAgain1()) {
220 ldr = openObject1(curs, objectId);
221 if (ldr != null) {
222 return ldr;
225 return null;
228 private ObjectLoader openObjectImpl2(final WindowCursor curs,
229 final String objectName, final AnyObjectId objectId)
230 throws IOException {
231 ObjectLoader ldr;
233 ldr = openObject2(curs, objectName, objectId);
234 if (ldr != null) {
235 return ldr;
237 for (final ObjectDatabase alt : getAlternates()) {
238 ldr = alt.openObjectImpl2(curs, objectName, objectId);
239 if (ldr != null) {
240 return ldr;
243 return null;
247 * Fast half of {@link #openObject(WindowCursor, AnyObjectId)}.
249 * @param curs
250 * temporary working space associated with the calling thread.
251 * @param objectId
252 * identity of the object to open.
253 * @return a {@link ObjectLoader} for accessing the data of the named
254 * object, or null if the object does not exist.
255 * @throws IOException
257 protected abstract ObjectLoader openObject1(WindowCursor curs,
258 AnyObjectId objectId) throws IOException;
261 * Slow half of {@link #openObject(WindowCursor, AnyObjectId)}.
263 * @param curs
264 * temporary working space associated with the calling thread.
265 * @param objectName
266 * name of the object to open.
267 * @param objectId
268 * identity of the object to open.
269 * @return a {@link ObjectLoader} for accessing the data of the named
270 * object, or null if the object does not exist.
271 * @throws IOException
273 protected ObjectLoader openObject2(WindowCursor curs, String objectName,
274 AnyObjectId objectId) throws IOException {
275 // Assume the search took place during openObject1.
276 return null;
280 * Open the object from all packs containing it.
281 * <p>
282 * If any alternates are present, their packs are also considered.
284 * @param out
285 * result collection of loaders for this object, filled with
286 * loaders from all packs containing specified object
287 * @param curs
288 * temporary working space associated with the calling thread.
289 * @param objectId
290 * id of object to search for
291 * @throws IOException
293 final void openObjectInAllPacks(final Collection<PackedObjectLoader> out,
294 final WindowCursor curs, final AnyObjectId objectId)
295 throws IOException {
296 openObjectInAllPacks1(out, curs, objectId);
297 for (final ObjectDatabase alt : getAlternates()) {
298 alt.openObjectInAllPacks1(out, curs, objectId);
303 * Open the object from all packs containing it.
305 * @param out
306 * result collection of loaders for this object, filled with
307 * loaders from all packs containing specified object
308 * @param curs
309 * temporary working space associated with the calling thread.
310 * @param objectId
311 * id of object to search for
312 * @throws IOException
314 void openObjectInAllPacks1(Collection<PackedObjectLoader> out,
315 WindowCursor curs, AnyObjectId objectId) throws IOException {
316 // Assume no pack support
320 * @return true if the fast-half search should be tried again.
322 protected boolean tryAgain1() {
323 return false;
327 * Get the alternate databases known to this database.
329 * @return the alternate list. Never null, but may be an empty array.
331 public final ObjectDatabase[] getAlternates() {
332 ObjectDatabase[] r = alternates.get();
333 if (r == null) {
334 synchronized (alternates) {
335 r = alternates.get();
336 if (r == null) {
337 try {
338 r = loadAlternates();
339 } catch (IOException e) {
340 r = NO_ALTERNATES;
342 alternates.set(r);
346 return r;
350 * Load the list of alternate databases into memory.
351 * <p>
352 * This method is invoked by {@link #getAlternates()} if the alternate list
353 * has not yet been populated, or if {@link #closeAlternates()} has been
354 * called on this instance and the alternate list is needed again.
355 * <p>
356 * If the alternate array is empty, implementors should consider using the
357 * constant {@link #NO_ALTERNATES}.
359 * @return the alternate list for this database.
360 * @throws IOException
361 * the alternate list could not be accessed. The empty alternate
362 * array {@link #NO_ALTERNATES} will be assumed by the caller.
364 protected ObjectDatabase[] loadAlternates() throws IOException {
365 return NO_ALTERNATES;