-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
573 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
fcrepo-kernel-api/src/main/java/org/fcrepo/kernel/api/cache/UserTypesCache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Licensed to DuraSpace under one or more contributor license agreements. | ||
* See the NOTICE file distributed with this work for additional information | ||
* regarding copyright ownership. | ||
* | ||
* DuraSpace licenses this file to you under the Apache License, | ||
* Version 2.0 (the "License"); you may not use this file except in | ||
* compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.fcrepo.kernel.api.cache; | ||
|
||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.function.Supplier; | ||
|
||
import org.fcrepo.kernel.api.RdfStream; | ||
import org.fcrepo.kernel.api.identifiers.FedoraId; | ||
|
||
/** | ||
* Cache of user RDF types. This cache has two levels. Types are cached at the session level as well as globally. | ||
* This is necessary to support long-running transactions that can span multiple requests. | ||
* | ||
* @author pwinckles | ||
*/ | ||
public interface UserTypesCache { | ||
|
||
/** | ||
* Gets the user RDF types for the specified resource from the cache. First, the session's cache is checked. | ||
* If the types were not found, then the global cache is checked. If not in either cache, then the rdfProvider | ||
* is called to load the resource's RDF from which the types are parsed, cached, and returned. | ||
* | ||
* This method should NOT be called on binary resources. | ||
* | ||
* @param resourceId the id of the resource | ||
* @param sessionId the id of the current session | ||
* @param rdfProvider the provider that is called, if needed, to load the resource's rdf | ||
* @return the resource's user RDF types | ||
*/ | ||
List<URI> getUserTypes(final FedoraId resourceId, | ||
final String sessionId, | ||
final Supplier<RdfStream> rdfProvider); | ||
|
||
/** | ||
* Extracts the user RDF types from the RDF and caches them in the session level cache. | ||
* | ||
* @param resourceId the id of the resource | ||
* @param rdf the resource's RDF | ||
* @param sessionId the session to cache the types in | ||
*/ | ||
void cacheUserTypes(final FedoraId resourceId, | ||
final RdfStream rdf, | ||
final String sessionId); | ||
|
||
/** | ||
* Caches the user RDF types in the session level cache. | ||
* | ||
* @param resourceId the id of the resource | ||
* @param userTypes the resource's types | ||
* @param sessionId the session to cache the types in | ||
*/ | ||
void cacheUserTypes(final FedoraId resourceId, | ||
final List<URI> userTypes, | ||
final String sessionId); | ||
|
||
/** | ||
* Merges the session level cache into the global cache. | ||
* | ||
* @param sessionId the id of the session to merge | ||
*/ | ||
void mergeSessionCache(final String sessionId); | ||
|
||
/** | ||
* Drops a session level cache without merging it into the global cache. | ||
* | ||
* @param sessionId the id of the session cache to drop | ||
*/ | ||
void dropSessionCache(final String sessionId); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
fcrepo-kernel-impl/src/main/java/org/fcrepo/kernel/impl/cache/UserTypesCacheImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* | ||
* Licensed to DuraSpace under one or more contributor license agreements. | ||
* See the NOTICE file distributed with this work for additional information | ||
* regarding copyright ownership. | ||
* | ||
* DuraSpace licenses this file to you under the Apache License, | ||
* Version 2.0 (the "License"); you may not use this file except in | ||
* compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.fcrepo.kernel.impl.cache; | ||
|
||
import static java.util.stream.Collectors.toList; | ||
import static org.apache.jena.vocabulary.RDF.type; | ||
|
||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.function.Supplier; | ||
|
||
import org.fcrepo.config.FedoraPropsConfig; | ||
import org.fcrepo.kernel.api.RdfStream; | ||
import org.fcrepo.kernel.api.ReadOnlyTransaction; | ||
import org.fcrepo.kernel.api.cache.UserTypesCache; | ||
import org.fcrepo.kernel.api.identifiers.FedoraId; | ||
|
||
import org.apache.jena.graph.Triple; | ||
import org.springframework.stereotype.Component; | ||
|
||
import com.github.benmanes.caffeine.cache.Cache; | ||
import com.github.benmanes.caffeine.cache.Caffeine; | ||
|
||
/** | ||
* Default UserTypesCache implementation | ||
* | ||
* @author pwinckles | ||
*/ | ||
@Component | ||
public class UserTypesCacheImpl implements UserTypesCache { | ||
|
||
private final Cache<FedoraId, List<URI>> globalCache; | ||
private final Map<String, Cache<FedoraId, List<URI>>> sessionCaches; | ||
|
||
public UserTypesCacheImpl(final FedoraPropsConfig config) { | ||
this.globalCache = Caffeine.newBuilder() | ||
.maximumSize(config.getUserTypesCacheSize()) | ||
.expireAfterAccess(config.getUserTypesCacheTimeout(), TimeUnit.MINUTES) | ||
.build(); | ||
this.sessionCaches = new ConcurrentHashMap<>(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public List<URI> getUserTypes(final FedoraId resourceId, | ||
final String sessionId, | ||
final Supplier<RdfStream> rdfProvider) { | ||
if (isNotReadOnlySession(sessionId)) { | ||
final var sessionCache = getSessionCache(sessionId); | ||
|
||
return sessionCache.get(resourceId, k -> { | ||
return globalCache.get(resourceId, k2 -> { | ||
return extractRdfTypes(rdfProvider.get()); | ||
}); | ||
}); | ||
} else { | ||
return globalCache.get(resourceId, k -> { | ||
return extractRdfTypes(rdfProvider.get()); | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void cacheUserTypes(final FedoraId resourceId, | ||
final RdfStream rdf, | ||
final String sessionId) { | ||
if (isNotReadOnlySession(sessionId)) { | ||
getSessionCache(sessionId).put(resourceId, extractRdfTypes(rdf)); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void cacheUserTypes(final FedoraId resourceId, | ||
final List<URI> userTypes, | ||
final String sessionId) { | ||
if (isNotReadOnlySession(sessionId)) { | ||
getSessionCache(sessionId).put(resourceId, userTypes); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void mergeSessionCache(final String sessionId) { | ||
if (isNotReadOnlySession(sessionId)) { | ||
final var sessionCache = getSessionCache(sessionId); | ||
globalCache.putAll(sessionCache.asMap()); | ||
dropSessionCache(sessionId); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void dropSessionCache(final String sessionId) { | ||
if (isNotReadOnlySession(sessionId)) { | ||
sessionCaches.remove(sessionId); | ||
} | ||
} | ||
|
||
private Cache<FedoraId, List<URI>> getSessionCache(final String sessionId) { | ||
return sessionCaches.computeIfAbsent(sessionId, k -> { | ||
return Caffeine.newBuilder() | ||
.maximumSize(1024) | ||
.build(); | ||
}); | ||
} | ||
|
||
private List<URI> extractRdfTypes(final RdfStream rdf) { | ||
return rdf.filter(t -> t.predicateMatches(type.asNode())) | ||
.map(Triple::getObject) | ||
.map(t -> URI.create(t.toString())) | ||
.collect(toList()); | ||
} | ||
|
||
private boolean isNotReadOnlySession(final String sessionId) { | ||
return !ReadOnlyTransaction.READ_ONLY_TX_ID.equals(sessionId); | ||
} | ||
} |
Oops, something went wrong.