From cf5b77156876ac2205d4555203f3f24990462657 Mon Sep 17 00:00:00 2001 From: John Wagenleitner Date: Sun, 24 Jan 2016 11:12:38 -0800 Subject: [PATCH] Fix finalizeReference method override for ManagedReference subclasses --- .../groovy/util/ManagedConcurrentMap.java | 21 +++++++--- .../util/ManagedConcurrentValueMap.java | 4 +- .../groovy/util/ManagedDoubleKeyMap.java | 11 +++-- .../groovy/util/ManagedLinkedList.java | 1 + .../util/ManagedConcurrentMapTest.groovy | 41 +++++++++++++++++++ .../util/ManagedConcurrentValueMapTest.groovy | 38 +++++++++++++++++ .../util/ManagedDoubleKeyMapTest.groovy | 41 +++++++++++++++++++ 7 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy create mode 100644 src/test/org/codehaus/groovy/util/ManagedConcurrentValueMapTest.groovy create mode 100644 src/test/org/codehaus/groovy/util/ManagedDoubleKeyMapTest.groovy diff --git a/src/main/org/codehaus/groovy/util/ManagedConcurrentMap.java b/src/main/org/codehaus/groovy/util/ManagedConcurrentMap.java index 0c1a7c7791a..db44a002db2 100644 --- a/src/main/org/codehaus/groovy/util/ManagedConcurrentMap.java +++ b/src/main/org/codehaus/groovy/util/ManagedConcurrentMap.java @@ -76,9 +76,18 @@ public int getHash() { return hash; } - public void finalizeRef() { - super.finalizeReference(); + @Override + public void finalizeReference() { segment.removeEntry(this); + super.finalizeReference(); + } + + /** + * @deprecated use finalizeReference + */ + @Deprecated + public void finalizeRef() { + finalizeReference(); } } @@ -90,18 +99,20 @@ public EntryWithValue(ReferenceBundle bundle, Segment segment, K key, int hash, setValue(value); } + @Override public V getValue() { return value; } + @Override public void setValue(V value) { this.value = value; } - - public void finalizeRef() { + @Override + public void finalizeReference() { value = null; - super.finalizeRef(); + super.finalizeReference(); } } } \ No newline at end of file diff --git a/src/main/org/codehaus/groovy/util/ManagedConcurrentValueMap.java b/src/main/org/codehaus/groovy/util/ManagedConcurrentValueMap.java index a9d12c6fddf..f28ee68e0bd 100644 --- a/src/main/org/codehaus/groovy/util/ManagedConcurrentValueMap.java +++ b/src/main/org/codehaus/groovy/util/ManagedConcurrentValueMap.java @@ -22,7 +22,7 @@ /** * This is a basic implementation of a map able to forget its values. This - * map uses internally a ConcurrentHashMap, thus should be save for concurrency. + * map uses internally a ConcurrentHashMap, thus should be safe for concurrency. * hashcode and equals are used to find the entries and should thus be implemented * properly for the keys. This map does not support null keys. * @author Jochen "blackdrag" Theodorou @@ -67,8 +67,8 @@ public void put(final K key, V value) { ManagedReference ref = new ManagedReference(bundle, value) { @Override public void finalizeReference() { + internalMap.remove(key, this); super.finalizeReference(); - internalMap.remove(key, get()); } }; internalMap.put(key, ref); diff --git a/src/main/org/codehaus/groovy/util/ManagedDoubleKeyMap.java b/src/main/org/codehaus/groovy/util/ManagedDoubleKeyMap.java index 65b2ee6094a..9dfe170db8e 100644 --- a/src/main/org/codehaus/groovy/util/ManagedDoubleKeyMap.java +++ b/src/main/org/codehaus/groovy/util/ManagedDoubleKeyMap.java @@ -48,8 +48,10 @@ public Ref(ReferenceBundle bundle, K referent, Entry entry) { this.entry = entry; } - public void finalizeRef() { + @Override + public void finalizeReference() { this.entry.clean(); + super.finalizeReference(); } } @@ -87,8 +89,6 @@ public int getHash() { public void clean() { segment.removeEntry(this); - ref1.clear(); - ref2.clear(); } } @@ -99,17 +99,20 @@ public EntryWithValue(ReferenceBundle bundle, K1 key1, K2 key2, int hash, Segmen super(bundle, key1, key2, hash, segment); } + @Override public V getValue() { return value; } + @Override public void setValue(V value) { this.value = value; } + @Override public void clean() { - super.clean(); value = null; + super.clean(); } } } diff --git a/src/main/org/codehaus/groovy/util/ManagedLinkedList.java b/src/main/org/codehaus/groovy/util/ManagedLinkedList.java index cc06c2af2d1..5f7bab5d956 100644 --- a/src/main/org/codehaus/groovy/util/ManagedLinkedList.java +++ b/src/main/org/codehaus/groovy/util/ManagedLinkedList.java @@ -40,6 +40,7 @@ public Element(ReferenceBundle bundle, V value) { super(bundle, value); } + @Override public void finalizeReference() { if (previous != null && previous.next != null) { previous.next = next; diff --git a/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy b/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy new file mode 100644 index 00000000000..7fe81f62283 --- /dev/null +++ b/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy @@ -0,0 +1,41 @@ +/* + * 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.codehaus.groovy.util + +class ManagedConcurrentMapTest extends GroovyTestCase { + + ManagedConcurrentMap map = + new ManagedConcurrentMap(ReferenceBundle.getHardBundle()) + + void testEntriesRemoveSelfFromMapWhenFinalized() { + List> entries = [] + for (int i = 0; i < 5; i++) { + entries << map.getOrPut(new Object(), "Object ${i}") + } + + assert map.size() == 5 + assert map.fullSize() == 5 + + entries*.finalizeReference() + + assert map.size() == 0 + assert map.fullSize() == 0 + } + +} diff --git a/src/test/org/codehaus/groovy/util/ManagedConcurrentValueMapTest.groovy b/src/test/org/codehaus/groovy/util/ManagedConcurrentValueMapTest.groovy new file mode 100644 index 00000000000..90e59dd8b97 --- /dev/null +++ b/src/test/org/codehaus/groovy/util/ManagedConcurrentValueMapTest.groovy @@ -0,0 +1,38 @@ +/* + * 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.codehaus.groovy.util + +class ManagedConcurrentValueMapTest extends GroovyTestCase { + + ManagedConcurrentValueMap map = + new ManagedConcurrentValueMap(ReferenceBundle.getHardBundle()) + + void testEntriesRemoveSelfFromMapWhenFinalized() { + for (int i = 0; i < 5; i++) { + map.put("Key${i}", new Object()) + } + + assert map.@internalMap.size() == 5 + + Collection> values = map.@internalMap.values() + values*.finalizeReference() + + assert map.@internalMap.size() == 0 + } +} diff --git a/src/test/org/codehaus/groovy/util/ManagedDoubleKeyMapTest.groovy b/src/test/org/codehaus/groovy/util/ManagedDoubleKeyMapTest.groovy new file mode 100644 index 00000000000..82a90d9a4c6 --- /dev/null +++ b/src/test/org/codehaus/groovy/util/ManagedDoubleKeyMapTest.groovy @@ -0,0 +1,41 @@ +/* + * 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.codehaus.groovy.util + +class ManagedDoubleKeyMapTest extends GroovyTestCase { + + ManagedDoubleKeyMap map = + new ManagedDoubleKeyMap(ReferenceBundle.getHardBundle()) + + void testEntriesRemoveSelfFromMapWhenFinalized() { + def entries = [] + for (int i = 0; i < 5; i++) { + entries << map.getOrPut(new Object(), new Object(), "Value${i}") + } + + assert map.size() == 5 + assert map.fullSize() == 5 + + entries*.clean() + + assert map.size() == 0 + assert map.fullSize() == 0 + } + +}