@ -64,6 +64,7 @@ import java.util.HashMap;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
import java.util.Objects ;
import java.util.Set ;
import java.util.concurrent.atomic.AtomicReference ;
@ -117,6 +118,8 @@ public class ObjectDirectory extends FileObjectDatabase {
/** Maximum number of candidates offered as resolutions of abbreviation. */
private static final int RESOLVE_ABBREV_LIMIT = 256 ;
private final AlternateHandle handle = new AlternateHandle ( this ) ;
private final Config config ;
private final File objects ;
@ -294,26 +297,38 @@ public class ObjectDirectory extends FileObjectDatabase {
@Override
public boolean has ( AnyObjectId objectId ) {
return unpackedObjectCache . isUnpacked ( objectId )
| | hasPackedInSelfOrAlternate ( objectId )
| | hasLooseInSelfOrAlternate ( objectId ) ;
| | hasPackedInSelfOrAlternate ( objectId , null )
| | hasLooseInSelfOrAlternate ( objectId , null ) ;
}
private boolean hasPackedInSelfOrAlternate ( AnyObjectId objectId ) {
if ( hasPackedObject ( objectId ) )
private boolean hasPackedInSelfOrAlternate ( AnyObjectId objectId ,
Set < AlternateHandle . Id > skips ) {
if ( hasPackedObject ( objectId ) ) {
return true ;
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
if ( alt . db . hasPackedInSelfOrAlternate ( objectId ) )
return true ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
if ( alt . db . hasPackedInSelfOrAlternate ( objectId , skips ) ) {
return true ;
}
}
}
return false ;
}
private boolean hasLooseInSelfOrAlternate ( AnyObjectId objectId ) {
if ( fileFor ( objectId ) . exists ( ) )
private boolean hasLooseInSelfOrAlternate ( AnyObjectId objectId ,
Set < AlternateHandle . Id > skips ) {
if ( fileFor ( objectId ) . exists ( ) ) {
return true ;
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
if ( alt . db . hasLooseInSelfOrAlternate ( objectId ) )
return true ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
if ( alt . db . hasLooseInSelfOrAlternate ( objectId , skips ) ) {
return true ;
}
}
}
return false ;
}
@ -340,6 +355,12 @@ public class ObjectDirectory extends FileObjectDatabase {
@Override
void resolve ( Set < ObjectId > matches , AbbreviatedObjectId id )
throws IOException {
resolve ( matches , id , null ) ;
}
private void resolve ( Set < ObjectId > matches , AbbreviatedObjectId id ,
Set < AlternateHandle . Id > skips )
throws IOException {
// Go through the packs once. If we didn't find any resolutions
// scan for new packs and check once more.
int oldSize = matches . size ( ) ;
@ -376,10 +397,14 @@ public class ObjectDirectory extends FileObjectDatabase {
}
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
alt . db . resolve ( matches , id ) ;
if ( matches . size ( ) > RESOLVE_ABBREV_LIMIT )
return ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
alt . db . resolve ( matches , id , skips ) ;
if ( matches . size ( ) > RESOLVE_ABBREV_LIMIT ) {
return ;
}
}
}
}
@ -388,37 +413,50 @@ public class ObjectDirectory extends FileObjectDatabase {
throws IOException {
if ( unpackedObjectCache . isUnpacked ( objectId ) ) {
ObjectLoader ldr = openLooseObject ( curs , objectId ) ;
if ( ldr ! = null )
if ( ldr ! = null ) {
return ldr ;
}
}
ObjectLoader ldr = openPackedFromSelfOrAlternate ( curs , objectId ) ;
if ( ldr ! = null )
ObjectLoader ldr = openPackedFromSelfOrAlternate ( curs , objectId , null ) ;
if ( ldr ! = null ) {
return ldr ;
return openLooseFromSelfOrAlternate ( curs , objectId ) ;
}
return openLooseFromSelfOrAlternate ( curs , objectId , null ) ;
}
private ObjectLoader openPackedFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId objectId ) {
AnyObjectId objectId , Set < AlternateHandle . Id > skips ) {
ObjectLoader ldr = openPackedObject ( curs , objectId ) ;
if ( ldr ! = null )
if ( ldr ! = null ) {
return ldr ;
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
ldr = alt . db . openPackedFromSelfOrAlternate ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
ldr = alt . db . openPackedFromSelfOrAlternate ( curs , objectId , skips ) ;
if ( ldr ! = null ) {
return ldr ;
}
}
}
return null ;
}
private ObjectLoader openLooseFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId objectId ) throws IOException {
AnyObjectId objectId , Set < AlternateHandle . Id > skips )
throws IOException {
ObjectLoader ldr = openLooseObject ( curs , objectId ) ;
if ( ldr ! = null )
if ( ldr ! = null ) {
return ldr ;
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
ldr = alt . db . openLooseFromSelfOrAlternate ( curs , objectId ) ;
if ( ldr ! = null )
return ldr ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
ldr = alt . db . openLooseFromSelfOrAlternate ( curs , objectId , skips ) ;
if ( ldr ! = null ) {
return ldr ;
}
}
}
return null ;
}
@ -469,37 +507,49 @@ public class ObjectDirectory extends FileObjectDatabase {
throws IOException {
if ( unpackedObjectCache . isUnpacked ( id ) ) {
long len = getLooseObjectSize ( curs , id ) ;
if ( 0 < = len )
if ( 0 < = len ) {
return len ;
}
}
long len = getPackedSizeFromSelfOrAlternate ( curs , id ) ;
if ( 0 < = len )
long len = getPackedSizeFromSelfOrAlternate ( curs , id , null ) ;
if ( 0 < = len ) {
return len ;
return getLooseSizeFromSelfOrAlternate ( curs , id ) ;
}
return getLooseSizeFromSelfOrAlternate ( curs , id , null ) ;
}
private long getPackedSizeFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId id ) {
AnyObjectId id , Set < AlternateHandle . Id > skips ) {
long len = getPackedObjectSize ( curs , id ) ;
if ( 0 < = len )
if ( 0 < = len ) {
return len ;
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
len = alt . db . getPackedSizeFromSelfOrAlternate ( curs , id ) ;
if ( 0 < = len )
return len ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
len = alt . db . getPackedSizeFromSelfOrAlternate ( curs , id , skips ) ;
if ( 0 < = len ) {
return len ;
}
}
}
return - 1 ;
}
private long getLooseSizeFromSelfOrAlternate ( WindowCursor curs ,
AnyObjectId id ) throws IOException {
AnyObjectId id , Set < AlternateHandle . Id > skips ) throws IOException {
long len = getLooseObjectSize ( curs , id ) ;
if ( 0 < = len )
if ( 0 < = len ) {
return len ;
}
skips = addMe ( skips ) ;
for ( AlternateHandle alt : myAlternates ( ) ) {
len = alt . db . getLooseSizeFromSelfOrAlternate ( curs , id ) ;
if ( 0 < = len )
return len ;
if ( ! skips . contains ( alt . getId ( ) ) ) {
len = alt . db . getLooseSizeFromSelfOrAlternate ( curs , id , skips ) ;
if ( 0 < = len ) {
return len ;
}
}
}
return - 1 ;
}
@ -546,7 +596,12 @@ public class ObjectDirectory extends FileObjectDatabase {
@Override
void selectObjectRepresentation ( PackWriter packer , ObjectToPack otp ,
WindowCursor curs ) throws IOException {
WindowCursor curs ) throws IOException {
selectObjectRepresentation ( packer , otp , curs , null ) ;
}
private void selectObjectRepresentation ( PackWriter packer , ObjectToPack otp ,
WindowCursor curs , Set < AlternateHandle . Id > skips ) throws IOException {
PackList pList = packList . get ( ) ;
SEARCH : for ( ; ; ) {
for ( final PackFile p : pList . packs ) {
@ -567,8 +622,12 @@ public class ObjectDirectory extends FileObjectDatabase {
break SEARCH ;
}
for ( AlternateHandle h : myAlternates ( ) )
h . db . selectObjectRepresentation ( packer , otp , curs ) ;
skips = addMe ( skips ) ;
for ( AlternateHandle h : myAlternates ( ) ) {
if ( ! skips . contains ( h . getId ( ) ) ) {
h . db . selectObjectRepresentation ( packer , otp , curs , skips ) ;
}
}
}
private void handlePackError ( IOException e , PackFile p ) {
@ -930,6 +989,14 @@ public class ObjectDirectory extends FileObjectDatabase {
return alt ;
}
Set < AlternateHandle . Id > addMe ( Set < AlternateHandle . Id > skips ) {
if ( skips = = null ) {
skips = new HashSet < > ( ) ;
}
skips . add ( handle . getId ( ) ) ;
return skips ;
}
private AlternateHandle [ ] loadAlternates ( ) throws IOException {
final List < AlternateHandle > l = new ArrayList < > ( 4 ) ;
final BufferedReader br = open ( alternatesFile ) ;
@ -996,6 +1063,38 @@ public class ObjectDirectory extends FileObjectDatabase {
}
static class AlternateHandle {
static class Id {
String alternateId ;
public Id ( File object ) {
try {
this . alternateId = object . getCanonicalPath ( ) ;
} catch ( Exception e ) {
alternateId = null ;
}
}
@Override
public boolean equals ( Object o ) {
if ( o = = this ) {
return true ;
}
if ( o = = null | | ! ( o instanceof Id ) ) {
return false ;
}
Id aId = ( Id ) o ;
return Objects . equals ( alternateId , aId . alternateId ) ;
}
@Override
public int hashCode ( ) {
if ( alternateId = = null ) {
return 1 ;
}
return alternateId . hashCode ( ) ;
}
}
final ObjectDirectory db ;
AlternateHandle ( ObjectDirectory db ) {
@ -1005,6 +1104,10 @@ public class ObjectDirectory extends FileObjectDatabase {
void close ( ) {
db . close ( ) ;
}
public Id getId ( ) {
return db . getAlternateId ( ) ;
}
}
static class AlternateRepository extends AlternateHandle {
@ -1029,4 +1132,8 @@ public class ObjectDirectory extends FileObjectDatabase {
CachedObjectDirectory newCachedFileObjectDatabase ( ) {
return new CachedObjectDirectory ( this ) ;
}
AlternateHandle . Id getAlternateId ( ) {
return new AlternateHandle . Id ( objects ) ;
}
}