@ -200,31 +200,19 @@ public class ObjectDirectory extends FileObjectDatabase {
unpackedObjectCache . clear ( ) ;
unpackedObjectCache . clear ( ) ;
final PackList packs = packList . get ( ) ;
final PackList packs = packList . get ( ) ;
packList . set ( NO_PACKS ) ;
if ( packs ! = NO_PACKS & & packList . compareAndSet ( packs , NO_PACKS ) ) {
for ( final PackFile p : packs . packs )
for ( PackFile p : packs . packs )
p . close ( ) ;
p . close ( ) ;
}
// Fully close all loaded alternates and clear the alternate list.
// Fully close all loaded alternates and clear the alternate list.
AlternateHandle [ ] alt = alternates . get ( ) ;
AlternateHandle [ ] alt = alternates . get ( ) ;
if ( alt ! = null ) {
if ( alt ! = null & & alternates . compareAndSet ( alt , null ) ) {
alternates . set ( null ) ;
for ( final AlternateHandle od : alt )
for ( final AlternateHandle od : alt )
od . close ( ) ;
od . close ( ) ;
}
}
}
}
/ * *
* Compute the location of a loose object file .
*
* @param objectId
* identity of the loose object to map to the directory .
* @return location of the object , if it were to exist as a loose object .
* /
@Override
public File fileFor ( final AnyObjectId objectId ) {
return super . fileFor ( objectId ) ;
}
/ * *
/ * *
* @return unmodifiable collection of all known pack files local to this
* @return unmodifiable collection of all known pack files local to this
* directory . Most recent packs are presented first . Packs most
* directory . Most recent packs are presented first . Packs most
@ -277,37 +265,64 @@ public class ObjectDirectory extends FileObjectDatabase {
@Override
@Override
public String toString ( ) {
public String toString ( ) {
return "ObjectDirectory[" + getDirectory ( ) + "]" ; //$NON-NLS-1$
return "ObjectDirectory[" + getDirectory ( ) + "]" ; //$NON-NLS-1$ //$NON-NLS-2$
}
}
boolean hasObject1 ( final AnyObjectId objectId ) {
@Override
if ( unpackedObjectCache . isUnpacked ( objectId ) )
public boolean has ( AnyObjectId objectId ) {
return unpackedObjectCache . isUnpacked ( objectId )
| | hasPackedInSelfOrAlternate ( objectId )
| | hasLooseInSelfOrAlternate ( objectId ) ;
}
private boolean hasPackedInSelfOrAlternate ( AnyObjectId objectId ) {
if ( hasPackedObject ( objectId ) )
return true ;
return true ;
for ( final PackFile p : packList . get ( ) . packs ) {
for ( AlternateHandle alt : myAlternates ( ) ) {
try {
if ( alt . db . hasPackedInSelfOrAlternate ( objectId ) )
if ( p . hasObject ( objectId ) ) {
return true ;
}
return false ;
}
private boolean hasLooseInSelfOrAlternate ( AnyObjectId objectId ) {
if ( fileFor ( objectId ) . exists ( ) )
return true ;
return true ;
for ( AlternateHandle alt : myAlternates ( ) ) {
if ( alt . db . hasLooseInSelfOrAlternate ( objectId ) )
return true ;
}
return false ;
}
}
boolean hasPackedObject ( AnyObjectId objectId ) {
PackList pList ;
do {
pList = packList . get ( ) ;
for ( PackFile p : pList . packs ) {
try {
if ( p . hasObject ( objectId ) )
return true ;
} catch ( IOException e ) {
} catch ( IOException e ) {
// The hasObject call should have only touched the index,
// The hasObject call should have only touched the index,
// so any failure here indicates the index is unreadable
// so any failure here indicates the index is unreadable
// by this process, and the pack is likewise not readable.
// by this process, and the pack is likewise not readable.
//
removePack ( p ) ;
removePack ( p ) ;
continue ;
}
}
}
}
} while ( searchPacksAgain ( pList ) ) ;
return false ;
return false ;
}
}
@Override
void resolve ( Set < ObjectId > matches , AbbreviatedObjectId id )
void resolve ( Set < ObjectId > matches , AbbreviatedObjectId id )
throws IOException {
throws IOException {
// Go through the packs once. If we didn't find any resolutions
// Go through the packs once. If we didn't find any resolutions
// scan for new packs and check once more.
// scan for new packs and check once more.
//
int oldSize = matches . size ( ) ;
int oldSize = matches . size ( ) ;
PackList pList = packList . get ( ) ;
PackList pList ;
for ( ; ; ) {
do {
pList = packList . get ( ) ;
for ( PackFile p : pList . packs ) {
for ( PackFile p : pList . packs ) {
try {
try {
p . resolve ( matches , id , RESOLVE_ABBREV_LIMIT ) ;
p . resolve ( matches , id , RESOLVE_ABBREV_LIMIT ) ;
@ -319,15 +334,7 @@ public class ObjectDirectory extends FileObjectDatabase {
if ( matches . size ( ) > RESOLVE_ABBREV_LIMIT )
if ( matches . size ( ) > RESOLVE_ABBREV_LIMIT )
return ;
return ;
}
}
if ( matches . size ( ) = = oldSize ) {
} while ( matches . size ( ) = = oldSize & & searchPacksAgain ( pList ) ) ;
PackList nList = scanPacks ( pList ) ;
if ( nList = = pList | | nList . packs . length = = 0 )
break ;
pList = nList ;
continue ;
}
break ;
}
String fanOut = id . name ( ) . substring ( 0 , 2 ) ;
String fanOut = id . name ( ) . substring ( 0 , 2 ) ;
String [ ] entries = new File ( getDirectory ( ) , fanOut ) . list ( ) ;
String [ ] entries = new File ( getDirectory ( ) , fanOut ) . list ( ) ;
@ -354,74 +361,164 @@ public class ObjectDirectory extends FileObjectDatabase {
}
}
}
}
ObjectLoader openObject1 ( final WindowCursor curs ,
@Override
final AnyObjectId objectId ) throws IOException {
ObjectLoader openObject ( WindowCursor curs , AnyObjectId objectId )
throws IOException {
if ( unpackedObjectCache . isUnpacked ( objectId ) ) {
if ( unpackedObjectCache . isUnpacked ( objectId ) ) {
ObjectLoader ldr = openObject2 ( curs , objectId . name ( ) , objectId ) ;
ObjectLoader ldr = openLoose Object ( curs , objectId ) ;
if ( ldr ! = null )
if ( ldr ! = null )
return ldr ;
return ldr ;
else
}
unpackedObjectCache . remove ( objectId ) ;
ObjectLoader ldr = openPackedFromSelfOrAlternate ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
return openLooseFromSelfOrAlternate ( curs , objectId ) ;
}
}
PackList pList = packList . get ( ) ;
private ObjectLoader openPackedFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId objectId ) {
ObjectLoader ldr = openPackedObject ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
for ( AlternateHandle alt : myAlternates ( ) ) {
ldr = alt . db . openPackedFromSelfOrAlternate ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
}
return null ;
}
private ObjectLoader openLooseFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId objectId ) throws IOException {
ObjectLoader ldr = openLooseObject ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
for ( AlternateHandle alt : myAlternates ( ) ) {
ldr = alt . db . openLooseFromSelfOrAlternate ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
}
return null ;
}
ObjectLoader openPackedObject ( WindowCursor curs , AnyObjectId objectId ) {
PackList pList ;
do {
SEARCH : for ( ; ; ) {
SEARCH : for ( ; ; ) {
for ( final PackFile p : pList . packs ) {
pList = packList . get ( ) ;
for ( PackFile p : pList . packs ) {
try {
try {
final ObjectLoader ldr = p . get ( curs , objectId ) ;
ObjectLoader ldr = p . get ( curs , objectId ) ;
if ( ldr ! = null )
if ( ldr ! = null )
return ldr ;
return ldr ;
} catch ( PackMismatchException e ) {
} catch ( PackMismatchException e ) {
// Pack was modified; refresh the entire pack list.
// Pack was modified; refresh the entire pack list.
//
if ( searchPacksAgain ( pList ) )
pList = scanPacks ( pList ) ;
continue SEARCH ;
continue SEARCH ;
} catch ( IOException e ) {
} catch ( IOException e ) {
// Assume the pack is corrupted.
// Assume the pack is corrupted.
//
removePack ( p ) ;
removePack ( p ) ;
}
}
}
}
break SEARCH ;
}
} while ( searchPacksAgain ( pList ) ) ;
return null ;
}
ObjectLoader openLooseObject ( WindowCursor curs , AnyObjectId id )
throws IOException {
try {
File path = fileFor ( id ) ;
FileInputStream in = new FileInputStream ( path ) ;
try {
unpackedObjectCache . add ( id ) ;
return UnpackedObject . open ( in , path , id , curs ) ;
} finally {
in . close ( ) ;
}
} catch ( FileNotFoundException noFile ) {
unpackedObjectCache . remove ( id ) ;
return null ;
return null ;
}
}
}
}
long getObjectSize1 ( final WindowCursor curs , final AnyObjectId objectId )
long getObjectSize ( WindowCursor curs , AnyObjectId i d)
throws IOException {
throws IOException {
PackList pList = packList . get ( ) ;
if ( unpackedObjectCache . isUnpacked ( id ) ) {
long len = getLooseObjectSize ( curs , id ) ;
if ( 0 < = len )
return len ;
}
long len = getPackedSizeFromSelfOrAlternate ( curs , id ) ;
if ( 0 < = len )
return len ;
return getLooseSizeFromSelfOrAlternate ( curs , id ) ;
}
private long getPackedSizeFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId id ) {
long len = getPackedObjectSize ( curs , id ) ;
if ( 0 < = len )
return len ;
for ( AlternateHandle alt : myAlternates ( ) ) {
len = alt . db . getPackedSizeFromSelfOrAlternate ( curs , id ) ;
if ( 0 < = len )
return len ;
}
return - 1 ;
}
private long getLooseSizeFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId id ) throws IOException {
long len = getLooseObjectSize ( curs , id ) ;
if ( 0 < = len )
return len ;
for ( AlternateHandle alt : myAlternates ( ) ) {
len = alt . db . getLooseSizeFromSelfOrAlternate ( curs , id ) ;
if ( 0 < = len )
return len ;
}
return - 1 ;
}
private long getPackedObjectSize ( WindowCursor curs , AnyObjectId id ) {
PackList pList ;
do {
SEARCH : for ( ; ; ) {
SEARCH : for ( ; ; ) {
for ( final PackFile p : pList . packs ) {
pList = packList . get ( ) ;
for ( PackFile p : pList . packs ) {
try {
try {
long sz = p . getObjectSize ( curs , objectId ) ;
long len = p . getObjectSize ( curs , i d) ;
if ( 0 < = sz )
if ( 0 < = len )
return sz ;
return len ;
} catch ( PackMismatchException e ) {
} catch ( PackMismatchException e ) {
// Pack was modified; refresh the entire pack list.
// Pack was modified; refresh the entire pack list.
//
if ( searchPacksAgain ( pList ) )
pList = scanPacks ( pList ) ;
continue SEARCH ;
continue SEARCH ;
} catch ( IOException e ) {
} catch ( IOException e ) {
// Assume the pack is corrupted.
// Assume the pack is corrupted.
//
removePack ( p ) ;
removePack ( p ) ;
}
}
}
}
return - 1 ;
break SEARCH ;
}
}
} while ( searchPacksAgain ( pList ) ) ;
return - 1 ;
}
}
@Override
private long getLooseObjectSize ( WindowCursor curs , AnyObjectId id )
long getObjectSize2 ( WindowCursor curs , String objectName ,
throws IOException {
AnyObjectId objectId ) throws IOException {
try {
try {
File path = fileFor ( objectName ) ;
FileInputStream in = new FileInputStream ( fileFor ( id ) ) ;
FileInputStream in = new FileInputStream ( path ) ;
try {
try {
return UnpackedObject . getSize ( in , objectId , curs ) ;
unpackedObjectCache . add ( id ) ;
return UnpackedObject . getSize ( in , id , curs ) ;
} finally {
} finally {
in . close ( ) ;
in . close ( ) ;
}
}
} catch ( FileNotFoundException noFile ) {
} catch ( FileNotFoundException noFile ) {
unpackedObjectCache . remove ( id ) ;
return - 1 ;
return - 1 ;
}
}
}
}
@ -454,28 +551,6 @@ public class ObjectDirectory extends FileObjectDatabase {
h . db . selectObjectRepresentation ( packer , otp , curs ) ;
h . db . selectObjectRepresentation ( packer , otp , curs ) ;
}
}
boolean hasObject2 ( final String objectName ) {
return fileFor ( objectName ) . exists ( ) ;
}
ObjectLoader openObject2 ( final WindowCursor curs ,
final String objectName , final AnyObjectId objectId )
throws IOException {
try {
File path = fileFor ( objectName ) ;
FileInputStream in = new FileInputStream ( path ) ;
try {
unpackedObjectCache . add ( objectId ) ;
return UnpackedObject . open ( in , path , objectId , curs ) ;
} finally {
in . close ( ) ;
}
} catch ( FileNotFoundException noFile ) {
unpackedObjectCache . remove ( objectId ) ;
return null ;
}
}
@Override
@Override
InsertLooseObjectResult insertUnpackedObject ( File tmp , ObjectId id ,
InsertLooseObjectResult insertUnpackedObject ( File tmp , ObjectId id ,
boolean createDuplicate ) throws IOException {
boolean createDuplicate ) throws IOException {
@ -530,11 +605,8 @@ public class ObjectDirectory extends FileObjectDatabase {
return InsertLooseObjectResult . FAILURE ;
return InsertLooseObjectResult . FAILURE ;
}
}
boolean tryAgain1 ( ) {
private boolean searchPacksAgain ( PackList old ) {
final PackList old = packList . get ( ) ;
return old . snapshot . isModified ( packDirectory ) & & old ! = scanPacks ( old ) ;
if ( old . snapshot . isModified ( packDirectory ) )
return old ! = scanPacks ( old ) ;
return false ;
}
}
Config getConfig ( ) {
Config getConfig ( ) {
@ -794,6 +866,20 @@ public class ObjectDirectory extends FileObjectDatabase {
return new AlternateHandle ( db ) ;
return new AlternateHandle ( db ) ;
}
}
/ * *
* Compute the location of a loose object file .
*
* @param objectId
* identity of the loose object to map to the directory .
* @return location of the object , if it were to exist as a loose object .
* /
public File fileFor ( AnyObjectId objectId ) {
String n = objectId . name ( ) ;
String d = n . substring ( 0 , 2 ) ;
String f = n . substring ( 2 ) ;
return new File ( new File ( getDirectory ( ) , d ) , f ) ;
}
private static final class PackList {
private static final class PackList {
/** State just before reading the pack directory. */
/** State just before reading the pack directory. */
final FileSnapshot snapshot ;
final FileSnapshot snapshot ;
@ -807,12 +893,37 @@ public class ObjectDirectory extends FileObjectDatabase {
}
}
}
}
static class AlternateHandle {
final ObjectDirectory db ;
AlternateHandle ( ObjectDirectory db ) {
this . db = db ;
}
void close ( ) {
db . close ( ) ;
}
}
static class AlternateRepository extends AlternateHandle {
final FileRepository repository ;
AlternateRepository ( FileRepository r ) {
super ( r . getObjectDatabase ( ) ) ;
repository = r ;
}
void close ( ) {
repository . close ( ) ;
}
}
@Override
@Override
public ObjectDatabase newCachedDatabase ( ) {
public ObjectDatabase newCachedDatabase ( ) {
return newCachedFileObjectDatabase ( ) ;
return newCachedFileObjectDatabase ( ) ;
}
}
FileObjectDatabase newCachedFileObjectDatabase ( ) {
CachedObjectDirectory newCachedFileObjectDatabase ( ) {
return new CachedObjectDirectory ( this ) ;
return new CachedObjectDirectory ( this ) ;
}
}
}
}