Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTable.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTable.java (date 1429003329000) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTable.java (date 1429017126000) @@ -51,6 +51,8 @@ private final SegmentTracker tracker; + private int count; + SegmentIdTable(SegmentTracker tracker) { this.tracker = tracker; } @@ -65,7 +67,6 @@ synchronized SegmentId getSegmentId(long msb, long lsb) { int first = getIndex(lsb); int index = first; - boolean shouldRefresh = false; WeakReference reference = references.get(index); while (reference != null) { @@ -75,14 +76,13 @@ && id.getLeastSignificantBits() == lsb) { return id; } - shouldRefresh = shouldRefresh || id == null; index = (index + 1) % references.size(); reference = references.get(index); } SegmentId id = new SegmentId(tracker, msb, lsb); references.set(index, new WeakReference(id)); - if (shouldRefresh) { + if (++count * 4 / 3 > references.size()) { refresh(); } return id; @@ -113,6 +113,7 @@ hashCollisions = hashCollisions || (i != getIndex(id)); } else { references.set(i, null); + count--; emptyReferences = true; } } @@ -158,6 +159,7 @@ if (strategy.canRemove(id)) { reference.clear(); references.set(i, null); + count--; dirty = true; } } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableTestIT.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableTestIT.java (date 1429017126000) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableTestIT.java (date 1429017126000) @@ -0,0 +1,67 @@ +/* + * 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.oak.plugins.segment; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import junit.framework.Assert; + +import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore; +import org.junit.Test; + +public class SegmentIdTableTestIT { + + /** + * OAK-2752 + */ + @Test + public void endlessSearchLoop() { + SegmentTracker tracker = new MemoryStore().getTracker(); + final SegmentIdTable tbl = new SegmentIdTable(tracker); + + List refs = new ArrayList(); + for (int i = 0; i < 1024; i++) { + refs.add(tbl.getSegmentId(i, i % 64)); + } + + Callable c = new Callable() { + + @Override + public SegmentId call() throws Exception { + // (2,1) doesn't exist + return tbl.getSegmentId(2, 1); + } + }; + Future f = Executors.newSingleThreadExecutor().submit(c); + SegmentId s = null; + try { + s = f.get(5, TimeUnit.SECONDS); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + Assert.assertNotNull(s); + Assert.assertEquals(2, s.getMostSignificantBits()); + Assert.assertEquals(1, s.getLeastSignificantBits()); + } +}