/*
 * 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.core.persistence.util;

import org.apache.commons.collections.map.LinkedMap;
import org.apache.jackrabbit.core.id.NodeId;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;

/**
 * Implements a LRU NodeId cache.
 */
public class LRUNodeIdCache {

    /**
     * The default logger
     */
    private static Logger log = LoggerFactory.getLogger(LRUNodeIdCache.class);

    /**
     * The maximum number of ids to cache
     */
    private long maxSize = 10240;

    /**
     * the number of cache hits
     */
    private long hits;

    /**
     * the number of cache misses
     */
    private long misses;

    /**
     * the map of cached ids
     */
    private final LinkedMap missing = new LinkedMap();

    /**
     * Checks if the given id is contained in this cached.
     *
     * @param id the id to check
     * @return <code>true</code> if the id is cached;
     *         <code>false</code> otherwise.
     */
    public boolean contains(NodeId id) {
        Object o = missing.remove(id);
        if (o == null) {
            misses++;
        } else {
            missing.put(id, id);
            hits++;
        }
        if (log.isInfoEnabled() && (hits + misses) % 10000 == 0) {
            log.info("num=" + missing.size() + "/" + maxSize + " hits=" + hits + " miss=" + misses);
        }
        return o != null;
    }

    /**
     * Puts the given id to this cache.
     * @param id the id to put.
     */
    public void put(NodeId id) {
        if (!missing.containsKey(id)) {
            if (missing.size() == maxSize) {
                missing.remove(0);
            }
            missing.put(id, id);
        }
    }

    /**
     * Removes the it to this cache
     * @param id the id to remove
     * @return <code>true</code> if the id was cached;
     *         <code>false</code> otherwise.
     */
    public boolean remove(NodeId id) {
        return missing.remove(id) != null;
    }

    /**
     * Clears this cache.
     */
    public void clear() {
        missing.clear();
    }

}

@@ -861,53 +861,55 @@
 ort 
-org.apache.commons.collections.map.LinkedMap;
+java.util.LinkedHashMap;%0Aimport java.util.Map;%0A
 %0Aimp
@@ -1273,20 +1273,32 @@
 private 
-long
+static final int
  maxSize
@@ -1509,31 +1509,83 @@
     
-private final LinkedMap
+@SuppressWarnings(%22serial%22)%0A    private final LinkedHashMap%3CNodeId, NodeId%3E
  mis
@@ -1590,16 +1590,24 @@
 issing =
+%0A       
  new Lin
@@ -1613,13 +1613,225 @@
 nked
-Map()
+HashMap%3CNodeId, NodeId%3E(maxSize * 2, 0.75f, true) %7B%0A            @Override%0A            protected boolean removeEldestEntry(Map.Entry%3CNodeId, NodeId%3E e) %7B%0A                return size() %3E maxSize;%0A            %7D%0A        %7D
 ;%0A%0A 
@@ -2046,32 +2046,45 @@
   */%0A    public 
+synchronized 
 boolean contains
@@ -2109,16 +2109,18 @@
     
-Object o
+boolean rv
  = m
@@ -2126,26 +2126,31 @@
 missing.
-remove(id)
+get(id) != null
 ;%0A      
@@ -2159,17 +2159,10 @@
 if (
-o == null
+rv
 ) %7B%0A
@@ -2173,21 +2173,19 @@
         
-misse
+hit
 s++;%0A   
@@ -2218,40 +2218,9 @@
 miss
-ing.put(id, id);%0A            hit
+e
 s++;
@@ -2427,17 +2427,10 @@
 urn 
-o != null
+rv
 ;%0A  
@@ -2529,24 +2529,37 @@
 %0A    public 
+synchronized 
 void put(Nod
@@ -2572,146 +2572,8 @@
 ) %7B%0A
-        if (!missing.containsKey(id)) %7B%0A            if (missing.size() == maxSize) %7B%0A                missing.remove(0);%0A            %7D%0A    
     
@@ -2597,26 +2597,16 @@
 d, id);%0A
-        %7D%0A
     %7D%0A%0A 
@@ -2801,16 +2801,29 @@
  public 
+synchronized 
 boolean 
@@ -2945,16 +2945,29 @@
  public 
+synchronized 
 void cle

Improve read/write concurrency