Skip to content

Commit c1a99a1

Browse files
authored
Rewrite store-query methods that use stream() and intercept/wrap store-query for metrics (#1461)
* Rewrite store-query methods that use stream() and intercept/wrap store-query for metrics We cannot use the @measure annotation in ArtifactStoreQuery, since that class is instantiated a variable number of calls for each user request, and instances hold state supporting the fluent API. The StoreDataManager decorator wraps ArtifactStoreQuery results from the query() method in a query class that measures query calls, delegating the actual query to the instance that comes from the underlying StoreDataManager delegate. StoreDataManager stream / getAll methods rely on having in-memory access to ALL of the ArtifactStore instances, and also on having a small enough instance count to make iterating through all of them feasible. In our production environment, both of these assumptions are violated. We need a better way to access this information, but to start I've refactored DefaultArtifactStoreQuery methods that use streams and getAll in the StoreDataManager so they won't do that. In the case of retrieving the stores that are in the membership tree of a particular group, I've rewritten that to avoid recursion. In addition, I've added a keyStream() method to ArtifactStoreQuery and a streamArtifactStoreKeys() method to StoreDataManager. This SHOULD be something that we can optimize, ensuring all keys are available in-memory or easy to deserialize with minimum overhead. We can do a lot of filtering based on the key alone, then additional filtering can be applied with the matching stores, which would be retrieved directly by key from the filtered keys in these calls. * remove duplicate dependencies in 2 poms * Separate metered-db stuff to break dependency cycle, and fix a few compilation / unit test problems
1 parent 85571cd commit c1a99a1

File tree

17 files changed

+944
-59
lines changed

17 files changed

+944
-59
lines changed

addons/httprox/common/pom.xml

-4
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,6 @@
8080
<artifactId>indy-filer-default</artifactId>
8181
<scope>test</scope>
8282
</dependency>
83-
<dependency>
84-
<groupId>org.commonjava.indy</groupId>
85-
<artifactId>indy-subsys-jaxrs</artifactId>
86-
</dependency>
8783
<dependency>
8884
<groupId>org.commonjava.indy</groupId>
8985
<artifactId>indy-folo-common</artifactId>

api/src/main/java/org/commonjava/indy/data/ArtifactStoreQuery.java

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ Stream<T> stream()
6767
Stream<T> stream( Predicate<ArtifactStore> filter )
6868
throws IndyDataException;
6969

70+
Stream<StoreKey> keyStream()
71+
throws IndyDataException;
72+
73+
Stream<StoreKey> keyStream( Predicate<StoreKey> filterPredicate )
74+
throws IndyDataException;
75+
7076
List<T> getAll( Predicate<ArtifactStore> filter )
7177
throws IndyDataException;
7278

api/src/main/java/org/commonjava/indy/data/DelegatingArtifactStoreQuery.java

+14
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ public Stream<T> stream( final Predicate<ArtifactStore> filter )
120120
return delegate.stream( filter );
121121
}
122122

123+
@Override
124+
public Stream<StoreKey> keyStream()
125+
throws IndyDataException
126+
{
127+
return delegate.keyStream();
128+
}
129+
130+
@Override
131+
public Stream<StoreKey> keyStream( final Predicate<StoreKey> filterPredicate )
132+
throws IndyDataException
133+
{
134+
return null;
135+
}
136+
123137
@Override
124138
public List<T> getAll( final Predicate<ArtifactStore> filter )
125139
throws IndyDataException

api/src/main/java/org/commonjava/indy/data/StoreDataManager.java

+5
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,9 @@ void reload()
129129
boolean isReadonly( ArtifactStore store );
130130

131131
boolean isEmpty();
132+
133+
/**
134+
* Stream of StoreKey instances present in the system.
135+
*/
136+
Stream<StoreKey> streamArtifactStoreKeys();
132137
}

db/common/src/main/java/org/commonjava/indy/db/common/AbstractStoreDataManager.java

+3
Original file line numberDiff line numberDiff line change
@@ -246,17 +246,20 @@ public abstract void clear( final ChangeSummary summary )
246246
throws IndyDataException;
247247

248248
@Override
249+
@Measure
249250
public abstract Set<ArtifactStore> getAllArtifactStores()
250251
throws IndyDataException;
251252

252253
@Override
254+
@Measure
253255
public Stream<ArtifactStore> streamArtifactStores()
254256
throws IndyDataException
255257
{
256258
return getAllArtifactStores().stream();
257259
}
258260

259261
@Override
262+
@Measure
260263
public abstract Map<StoreKey, ArtifactStore> getArtifactStoresByKey();
261264

262265
@Override

db/common/src/main/java/org/commonjava/indy/db/common/DefaultArtifactStoreQuery.java

+121-50
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636
import java.util.Arrays;
3737
import java.util.Collection;
3838
import java.util.Collections;
39-
import java.util.HashMap;
4039
import java.util.HashSet;
40+
import java.util.LinkedList;
4141
import java.util.List;
42-
import java.util.Map;
4342
import java.util.Set;
43+
import java.util.concurrent.atomic.AtomicReference;
4444
import java.util.function.Predicate;
4545
import java.util.stream.Collectors;
4646
import java.util.stream.Stream;
@@ -162,13 +162,15 @@ public List<T> getAll()
162162
}
163163

164164
@Override
165+
@Measure
165166
public Stream<T> stream()
166167
throws IndyDataException
167168
{
168169
return stream( store -> true );
169170
}
170171

171172
@Override
173+
@Measure
172174
public Stream<T> stream( Predicate<ArtifactStore> filter )
173175
throws IndyDataException
174176
{
@@ -219,6 +221,7 @@ public List<T> getAll( Predicate<ArtifactStore> filter )
219221
}
220222

221223
@Override
224+
@Measure
222225
public List<T> getAllByDefaultPackageTypes()
223226
throws IndyDataException
224227
{
@@ -233,6 +236,7 @@ public List<T> getAllByDefaultPackageTypes()
233236
}
234237

235238
@Override
239+
@Measure
236240
public T getByName( String name )
237241
throws IndyDataException
238242
{
@@ -251,9 +255,7 @@ public boolean containsByName( String name )
251255
public Set<Group> getGroupsContaining( StoreKey storeKey )
252256
throws IndyDataException
253257
{
254-
return new DefaultArtifactStoreQuery<>( dataManager, storeKey.getPackageType(), enabled,
255-
Group.class ).stream(
256-
store -> ( (Group) store ).getConstituents().contains( storeKey ) ).collect( Collectors.toSet() );
258+
return getAllGroups().stream().filter( g -> g.getConstituents().contains( storeKey ) ).collect( Collectors.toSet() );
257259
}
258260

259261
@Override
@@ -374,21 +376,15 @@ public List<RemoteRepository> getRemoteRepositoryByUrl( String url )
374376
public List<ArtifactStore> getOrderedConcreteStoresInGroup( final String groupName )
375377
throws IndyDataException
376378
{
377-
Map<StoreKey, ArtifactStore> stores = new HashMap<>();
378-
stream().forEach( s -> stores.put( s.getKey(), s ) );
379-
380-
return getGroupOrdering( groupName, stores, false, true );
379+
return getGroupOrdering( groupName, false, true );
381380
}
382381

383382
@Override
384383
@Measure
385384
public List<ArtifactStore> getOrderedStoresInGroup( final String groupName )
386385
throws IndyDataException
387386
{
388-
Map<StoreKey, ArtifactStore> stores = new HashMap<>();
389-
stream().forEach( s -> stores.put( s.getKey(), s ) );
390-
391-
return getGroupOrdering( groupName, stores, true, false );
387+
return getGroupOrdering( groupName, true, false );
392388
}
393389

394390
@Override
@@ -417,8 +413,8 @@ public Set<Group> getGroupsAffectedBy( Collection<StoreKey> keys )
417413

418414
Set<StoreKey> processed = new HashSet<>();
419415

420-
Set<Group> all = new DefaultArtifactStoreQuery<>( dataManager, toProcess.get( 0 ).getPackageType(), null,
421-
Group.class ).stream().collect( Collectors.toSet() );
416+
Set<StoreKey> all = new DefaultArtifactStoreQuery<>( dataManager, toProcess.get( 0 ).getPackageType(), null,
417+
Group.class ).keyStream().collect( Collectors.toSet() );
422418

423419
while ( !toProcess.isEmpty() )
424420
{
@@ -433,8 +429,10 @@ public Set<Group> getGroupsAffectedBy( Collection<StoreKey> keys )
433429
// use this to avoid reprocessing groups we've already encountered.
434430
processed.add( next );
435431

436-
for ( ArtifactStore store : all )
432+
for ( StoreKey key : all )
437433
{
434+
ArtifactStore store = dataManager.getArtifactStore( key );
435+
438436
if ( !processed.contains( store.getKey() ) && ( store instanceof Group ) )
439437
{
440438
Group g = (Group) store;
@@ -452,27 +450,76 @@ public Set<Group> getGroupsAffectedBy( Collection<StoreKey> keys )
452450
return groups;
453451
}
454452

453+
public Stream<StoreKey> keyStream()
454+
{
455+
return keyStream( null );
456+
}
457+
458+
public Stream<StoreKey> keyStream( Predicate<StoreKey> filterPredicate )
459+
{
460+
return dataManager.streamArtifactStoreKeys().filter(key -> {
461+
if ( packageType != null && !key.getPackageType().equals( packageType ))
462+
{
463+
return false;
464+
}
465+
466+
if ( types != null && !types.isEmpty() && !types.contains( key.getType() ) )
467+
{
468+
return false;
469+
}
470+
471+
if ( filterPredicate != null && !filterPredicate.test( key ) )
472+
{
473+
return false;
474+
}
475+
476+
return true;
477+
});
478+
}
479+
455480
@Override
481+
@Measure
456482
public List<RemoteRepository> getAllRemoteRepositories()
457483
throws IndyDataException
458484
{
459-
return new DefaultArtifactStoreQuery<>( dataManager, packageType, enabled,
460-
RemoteRepository.class ).getAll();
485+
return getAllOfType( RemoteRepository.class );
461486
}
462487

463488
@Override
489+
@Measure
464490
public List<HostedRepository> getAllHostedRepositories()
465491
throws IndyDataException
466492
{
467-
return new DefaultArtifactStoreQuery<>( dataManager, packageType, enabled,
468-
HostedRepository.class ).getAll();
493+
return getAllOfType( HostedRepository.class );
469494
}
470495

471496
@Override
497+
@Measure
472498
public List<Group> getAllGroups()
473499
throws IndyDataException
474500
{
475-
return new DefaultArtifactStoreQuery<>( dataManager, packageType, enabled, Group.class ).getAll();
501+
return getAllOfType( Group.class );
502+
}
503+
504+
private <T extends ArtifactStore> List<T> getAllOfType(Class<T> type)
505+
throws IndyDataException
506+
{
507+
List<StoreKey> keys = new DefaultArtifactStoreQuery<>( dataManager, packageType, enabled, type ).keyStream()
508+
.collect(
509+
Collectors
510+
.toList() );
511+
512+
List<T> stores = new ArrayList<>();
513+
for ( StoreKey key : keys )
514+
{
515+
T store = (T) dataManager.getArtifactStore( key );
516+
if ( store != null && ( enabled == null || store.isDisabled() == !enabled ) )
517+
{
518+
stores.add( store );
519+
}
520+
}
521+
522+
return stores;
476523
}
477524

478525
@Override
@@ -503,7 +550,7 @@ public DefaultArtifactStoreQuery<T> noPackageType()
503550
return this;
504551
}
505552

506-
private List<ArtifactStore> getGroupOrdering( final String groupName, final Map<StoreKey, ArtifactStore> stores,
553+
private List<ArtifactStore> getGroupOrdering( final String groupName,
507554
final boolean includeGroups, final boolean recurseGroups )
508555
throws IndyDataException
509556
{
@@ -512,55 +559,79 @@ private List<ArtifactStore> getGroupOrdering( final String groupName, final Map<
512559
throw new IndyDataException( "packageType must be set on the query before calling this method!" );
513560
}
514561

515-
final Group master = (Group) stores.get( new StoreKey( packageType, StoreType.group, groupName ) );
562+
final Group master = (Group) dataManager.getArtifactStore( new StoreKey( packageType, StoreType.group, groupName ) );
516563
if ( master == null )
517564
{
518565
return Collections.emptyList();
519566
}
520567

521568
final List<ArtifactStore> result = new ArrayList<>();
522-
recurseGroup( master, stores, result, new HashSet<>(), includeGroups, recurseGroups );
569+
recurseGroup( master, result, new HashSet<>(), includeGroups, recurseGroups );
523570

524571
return result;
525572
}
526573

527-
private void recurseGroup( final Group master, final Map<StoreKey, ArtifactStore> stores,
574+
private void recurseGroup( final Group master,
528575
final List<ArtifactStore> result, final Set<StoreKey> seen, final boolean includeGroups,
529576
final boolean recurseGroups )
577+
throws IndyDataException
530578
{
531-
if ( master == null || master.isDisabled() && Boolean.TRUE.equals( enabled ) )
532-
{
533-
return;
534-
}
579+
AtomicReference<IndyDataException> errorRef = new AtomicReference<>();
580+
LinkedList<Group> toCheck = new LinkedList<>();
581+
toCheck.add( master );
535582

536-
List<StoreKey> members = new ArrayList<>( master.getConstituents() );
537-
if ( includeGroups )
583+
while ( !toCheck.isEmpty() )
538584
{
539-
result.add( master );
540-
}
585+
Group next = toCheck.removeFirst();
541586

542-
members.forEach( ( key ) ->
543-
{
544-
if ( !seen.contains( key ) )
587+
if ( next == null || next.isDisabled() && Boolean.TRUE.equals( enabled ) )
588+
{
589+
return;
590+
}
591+
592+
List<StoreKey> members = new ArrayList<>( next.getConstituents() );
593+
if ( includeGroups )
594+
{
595+
result.add( next );
596+
}
597+
598+
// TODO: Need to refactor away from actual recursion.
599+
members.forEach( ( key ) ->
545600
{
546-
seen.add( key );
547-
final StoreType type = key.getType();
548-
if ( recurseGroups && type == StoreType.group )
549-
{
550-
// if we're here, we're definitely recursing groups...
551-
recurseGroup( (Group) stores.get( key ), stores, result, seen, includeGroups,
552-
true );
553-
}
554-
else
601+
if ( !seen.contains( key ) )
555602
{
556-
final ArtifactStore store = stores.get( key );
557-
if ( store != null && !( store.isDisabled() && Boolean.TRUE.equals( enabled ) ) )
603+
seen.add( key );
604+
final StoreType type = key.getType();
605+
try
606+
{
607+
if ( recurseGroups && type == StoreType.group )
608+
{
609+
// if we're here, we're definitely recursing groups...
610+
Group group = (Group) dataManager.getArtifactStore( key );
611+
toCheck.addFirst( group );
612+
}
613+
else
614+
{
615+
final ArtifactStore store = dataManager.getArtifactStore( key );
616+
if ( store != null && !( store.isDisabled() && Boolean.TRUE.equals( enabled ) ) )
617+
{
618+
result.add( store );
619+
}
620+
}
621+
}
622+
catch ( IndyDataException e )
558623
{
559-
result.add( store );
624+
errorRef.set(e);
560625
}
561626
}
562-
}
563-
} );
627+
} );
628+
629+
IndyDataException error = errorRef.get();
630+
if ( error != null )
631+
{
632+
throw error;
633+
}
634+
}
564635
}
565636

566637
}

0 commit comments

Comments
 (0)