You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by re...@apache.org on 2013/03/22 13:35:03 UTC
svn commit: r1459743 - in
/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav:
IdPathCache.java IdURICache.java URIResolverImpl.java
Author: reschke
Date: Fri Mar 22 12:35:03 2013
New Revision: 1459743
URL: http://svn.apache.org/r1459743
Log:
JCR-3535: Davex remoting should support absolute path hrefs (fix URI cache)
Added:
jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java (with props)
Removed:
jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdURICache.java
Modified:
jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java
Added: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java?rev=1459743&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java (added)
+++ jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java Fri Mar 22 12:35:03 2013
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.jackrabbit.spi2dav;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.jackrabbit.spi.ItemId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>IdPathCache</code> maintains a bidirectional LRU cache from itemId to its path.
+ */
+class IdPathCache {
+
+ private static Logger log = LoggerFactory.getLogger(IdPathCache.class);
+
+ private LRUCache<ItemId, String> idToPathCache;
+ private LRUCache<String, ItemId> pathToIdCache;
+
+ public IdPathCache(int limit) {
+ idToPathCache = new LRUCache<ItemId, String>(limit);
+ pathToIdCache = new LRUCache<String, ItemId>(limit);
+ }
+
+ public ItemId getItemId(String path) {
+ return pathToIdCache.get(path);
+ }
+
+ public String getPath(ItemId itemId) {
+ return idToPathCache.get(itemId);
+ }
+
+ public boolean containsPath(String path) {
+ return pathToIdCache.containsKey(path);
+ }
+
+ public boolean containsItemId(ItemId itemId) {
+ return idToPathCache.containsKey(itemId);
+ }
+
+ public void add(String path, ItemId itemId) {
+ pathToIdCache.put(path, itemId);
+ idToPathCache.put(itemId, path);
+ log.debug("Added: ItemId = " + itemId + " PATH = {}", path);
+ }
+
+ public void remove(String path) {
+ ItemId itemId = pathToIdCache.remove(path);
+ if (itemId != null) {
+ idToPathCache.remove(itemId);
+ }
+ log.debug("Removed: ItemId = " + itemId + " PATH = {}", path);
+ }
+
+ public void remove(ItemId itemId) {
+ String path = idToPathCache.remove(itemId);
+ if (path != null) {
+ pathToIdCache.remove(path);
+ }
+ log.debug("Removed: ItemId = " + itemId + " PATH = {}", path);
+ }
+
+ public void clear() {
+ idToPathCache.clear();
+ pathToIdCache.clear();
+ }
+
+ private class LRUCache<K, V> extends LinkedHashMap<K, V> {
+
+ private static final long serialVersionUID = -3911958540620392955L;
+
+ private final int limit;
+
+ public LRUCache(int limit) {
+ super(16, 0.75f, true);
+ this.limit = limit;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
+ return size() > limit;
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/IdPathCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java?rev=1459743&r1=1459742&r2=1459743&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/URIResolverImpl.java Fri Mar 22 12:35:03 2013
@@ -40,11 +40,14 @@ import org.apache.jackrabbit.webdav.prop
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.apache.jackrabbit.webdav.version.report.ReportInfo;
import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
import java.io.IOException;
+import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
@@ -53,13 +56,20 @@ import java.util.Map;
*/
class URIResolverImpl implements URIResolver {
+ private static Logger log = LoggerFactory.getLogger(URIResolverImpl.class);
+
+ /**
+ * @see <a href="https://issues.apache.org/jira/browse/JCR-3305">JCR-3305</a>: limit cache size
+ */
+ private static final int CACHESIZE = 10000;
+
private final URI repositoryUri;
private final RepositoryServiceImpl service;
private final Document domFactory;
// TODO: to-be-fixed. uri/id-caches don't get updated
// for each workspace a separate idUri-cache is created
- private final Map<String, IdURICache> idURICaches = new HashMap<String, IdURICache>();
+ private final Map<String, IdPathCache> idPathCaches = new HashMap<String, IdPathCache>();
URIResolverImpl(URI repositoryUri, RepositoryServiceImpl service, Document domFactory) {
this.repositoryUri = repositoryUri;
@@ -67,13 +77,14 @@ class URIResolverImpl implements URIReso
this.domFactory = domFactory;
}
- private IdURICache getCache(String workspaceName) {
- if (idURICaches.containsKey(workspaceName)) {
- return idURICaches.get(workspaceName);
+ private IdPathCache getCache(String workspaceName) {
+ IdPathCache cache = idPathCaches.get(workspaceName);
+ if (cache != null) {
+ return cache;
} else {
- IdURICache c = new IdURICache(getWorkspaceUri(workspaceName));
- idURICaches.put(workspaceName, c);
- return c;
+ IdPathCache emptyCache = new IdPathCache(CACHESIZE);
+ idPathCaches.put(workspaceName, emptyCache);
+ return emptyCache;
}
}
@@ -95,10 +106,10 @@ class URIResolverImpl implements URIReso
String getItemUri(ItemId itemId, String workspaceName, SessionInfo sessionInfo)
throws RepositoryException {
- IdURICache cache = getCache(workspaceName);
+ IdPathCache cache = getCache(workspaceName);
// check if uri is available from cache
if (cache.containsItemId(itemId)) {
- return cache.getUri(itemId);
+ return getUri(cache.getPath(itemId));
} else {
StringBuffer uriBuffer = new StringBuffer();
@@ -110,7 +121,7 @@ class URIResolverImpl implements URIReso
ItemId uuidId = (path == null) ? itemId : service.getIdFactory().createNodeId(uniqueID);
if (path != null && cache.containsItemId(uuidId)) {
// append uri of parent node, that is already cached
- uriBuffer.append(cache.getUri(uuidId));
+ uriBuffer.append(getUri(cache.getPath(uuidId)));
} else {
// try to request locate-by-uuid report to build the uri
ReportInfo rInfo = new ReportInfo(JcrRemotingConstants.REPORT_LOCATE_BY_UUID, ItemResourceConstants.NAMESPACE);
@@ -126,7 +137,7 @@ class URIResolverImpl implements URIReso
MultiStatus ms = rm.getResponseBodyAsMultiStatus();
if (ms.getResponses().length == 1) {
uriBuffer.append(ms.getResponses()[0].getHref());
- cache.add(ms.getResponses()[0].getHref(), uuidId);
+ cache.add(getPath(ms.getResponses()[0].getHref()), uuidId);
} else {
throw new ItemNotFoundException("Cannot identify item with uniqueID " + uniqueID);
}
@@ -155,7 +166,7 @@ class URIResolverImpl implements URIReso
}
String itemUri = uriBuffer.toString();
if (!cache.containsItemId(itemId)) {
- cache.add(itemUri, itemId);
+ cache.add(getPath(itemUri), itemId);
}
return itemUri;
}
@@ -163,7 +174,7 @@ class URIResolverImpl implements URIReso
NodeId buildNodeId(NodeId parentId, MultiStatusResponse response,
String workspaceName, NamePathResolver resolver) throws RepositoryException {
- IdURICache cache = getCache(workspaceName);
+ IdPathCache cache = getCache(workspaceName);
NodeId nodeId;
DavPropertySet propSet = response.getProperties(DavServletResponse.SC_OK);
@@ -181,15 +192,16 @@ class URIResolverImpl implements URIReso
}
}
// cache
- cache.add(response.getHref(), nodeId);
+ cache.add(getPath(response.getHref()), nodeId);
return nodeId;
}
PropertyId buildPropertyId(NodeId parentId, MultiStatusResponse response,
String workspaceName, NamePathResolver resolver) throws RepositoryException {
- IdURICache cache = getCache(workspaceName);
- if (cache.containsUri(response.getHref())) {
- ItemId id = cache.getItemId(response.getHref());
+ IdPathCache cache = getCache(workspaceName);
+ String path = getPath(response.getHref());
+ if (cache.containsPath(path)) {
+ ItemId id = cache.getItemId(path);
if (!id.denotesNode()) {
return (PropertyId) id;
}
@@ -200,22 +212,15 @@ class URIResolverImpl implements URIReso
Name name = resolver.getQName(propSet.get(JcrRemotingConstants.JCR_NAME_LN, ItemResourceConstants.NAMESPACE).getValue().toString());
PropertyId propertyId = service.getIdFactory().createPropertyId(parentId, name);
- cache.add(response.getHref(), propertyId);
+ cache.add(getPath(response.getHref()), propertyId);
return propertyId;
} catch (NameException e) {
throw new RepositoryException(e);
}
}
- void clearCacheEntries(ItemId itemId, SessionInfo sessionInfo) {
- IdURICache cache = getCache(sessionInfo.getWorkspaceName());
- if (cache.containsItemId(itemId)) {
- cache.remove(itemId);
- }
- }
-
void clearCacheEntries(SessionInfo sessionInfo) {
- IdURICache cache = getCache(sessionInfo.getWorkspaceName());
+ IdPathCache cache = getCache(sessionInfo.getWorkspaceName());
cache.clear();
}
@@ -233,10 +238,11 @@ class URIResolverImpl implements URIReso
}
private NodeId getNodeId(String uri, SessionInfo sessionInfo, boolean nodeIsGone) throws RepositoryException {
- IdURICache cache = getCache(sessionInfo.getWorkspaceName());
- if (cache.containsUri(uri)) {
+ IdPathCache cache = getCache(sessionInfo.getWorkspaceName());
+ String path = getPath(uri);
+ if (cache.containsPath(path)) {
// id has been accessed before and is cached
- ItemId id = cache.getItemId(uri);
+ ItemId id = cache.getItemId(path);
if (id.denotesNode()) {
return (NodeId) id;
}
@@ -281,6 +287,32 @@ class URIResolverImpl implements URIReso
}
}
+ /**
+ * @param uri the uri to be parsed
+ * @return the path (trailing slash removed) extracted from the given uri or <code>null</code> if the uri could not
+ * be parsed.
+ */
+ private String getPath(String uri) {
+ try {
+ String path = new java.net.URI(uri).getPath();
+ if (path.endsWith("/") && ! "/".equals(path)) {
+ return path.substring(0, path.length() - 1);
+ }
+ return path;
+ } catch (URISyntaxException e) {
+ log.warn("Failed to parse the URI = {}", uri);
+ }
+ return null;
+ }
+
+ private String getUri(String path) {
+ String baseUri = getRepositoryUri();
+ if (baseUri.endsWith("/")) {
+ return baseUri.substring(0, baseUri.length() - 1) + Text.escapePath(path);
+ }
+ return baseUri + Text.escapePath(path);
+ }
+
//-------------------------------------------------------< URI resolver >---
/**
* @inheritDoc
@@ -319,9 +351,10 @@ class URIResolverImpl implements URIReso
* @inheritDoc
*/
public PropertyId getPropertyId(String uri, SessionInfo sessionInfo) throws RepositoryException {
- IdURICache cache = getCache(sessionInfo.getWorkspaceName());
- if (cache.containsUri(uri)) {
- ItemId id = cache.getItemId(uri);
+ IdPathCache cache = getCache(sessionInfo.getWorkspaceName());
+ String path = getPath(uri);
+ if (cache.containsPath(path)) {
+ ItemId id = cache.getItemId(path);
if (!id.denotesNode()) {
return (PropertyId) id;
}
@@ -337,7 +370,7 @@ class URIResolverImpl implements URIReso
try {
Name name = service.getNamePathResolver(sessionInfo).getQName(propName);
PropertyId propertyId = service.getIdFactory().createPropertyId(parentId, name);
- cache.add(uri, propertyId);
+ cache.add(getPath(uri), propertyId);
return propertyId;
} catch (NameException e) {