View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.util;
21  
22  import java.lang.ref.ReferenceQueue;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Comparator;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.SortedMap;
29  import java.util.TreeMap;
30  import java.util.TreeSet;
31  
32  /**
33   * A SortedMap implementation that uses Soft Reference values
34   * internally to make it play well with the GC when in a low-memory
35   * situation. Use as a cache where you also need SortedMap functionality.
36   *
37   * @param <K> key class
38   * @param <V> value class
39   */
40  public class SoftValueSortedMap<K,V> implements SortedMap<K,V> {
41    private final SortedMap<K, SoftValue<K,V>> internalMap;
42    private final ReferenceQueue rq = new ReferenceQueue();
43  
44    /** Constructor */
45    public SoftValueSortedMap() {
46      this(new TreeMap<K, SoftValue<K,V>>());
47    }
48  
49    /**
50     * Constructor
51     * @param c comparator
52     */
53    public SoftValueSortedMap(final Comparator<K> c) {
54      this(new TreeMap<K, SoftValue<K,V>>(c));
55    }
56  
57    /** For headMap and tailMap support
58     * @param original object to wrap
59     */
60    private SoftValueSortedMap(SortedMap<K,SoftValue<K,V>> original) {
61      this.internalMap = original;
62    }
63  
64    /**
65     * Checks soft references and cleans any that have been placed on
66     * ReferenceQueue.  Call if get/put etc. are not called regularly.
67     * Internally these call checkReferences on each access.
68     * @return How many references cleared.
69     */
70    private int checkReferences() {
71      int i = 0;
72      for (Object obj; (obj = this.rq.poll()) != null;) {
73        i++;
74        //noinspection unchecked
75        this.internalMap.remove(((SoftValue<K,V>)obj).getKey());
76      }
77      return i;
78    }
79  
80    public synchronized V put(K key, V value) {
81      checkReferences();
82      SoftValue<K,V> oldValue = this.internalMap.put(key,
83        new SoftValue<K,V>(key, value, this.rq));
84      return oldValue == null ? null : oldValue.get();
85    }
86  
87    @SuppressWarnings("unchecked")
88    public synchronized void putAll(Map map) {
89      throw new RuntimeException("Not implemented");
90    }
91  
92    @SuppressWarnings({"SuspiciousMethodCalls"})
93    public synchronized V get(Object key) {
94      checkReferences();
95      SoftValue<K,V> value = this.internalMap.get(key);
96      if (value == null) {
97        return null;
98      }
99      if (value.get() == null) {
100       this.internalMap.remove(key);
101       return null;
102     }
103     return value.get();
104   }
105 
106   public synchronized V remove(Object key) {
107     checkReferences();
108     SoftValue<K,V> value = this.internalMap.remove(key);
109     return value == null ? null : value.get();
110   }
111 
112   public synchronized boolean containsKey(Object key) {
113     checkReferences();
114     return this.internalMap.containsKey(key);
115   }
116 
117   public synchronized boolean containsValue(Object value) {
118 /*    checkReferences();
119     return internalMap.containsValue(value);*/
120     throw new UnsupportedOperationException("Don't support containsValue!");
121   }
122 
123   public synchronized K firstKey() {
124     checkReferences();
125     return internalMap.firstKey();
126   }
127 
128   public synchronized K lastKey() {
129     checkReferences();
130     return internalMap.lastKey();
131   }
132 
133   public synchronized SoftValueSortedMap<K,V> headMap(K key) {
134     checkReferences();
135     return new SoftValueSortedMap<K,V>(this.internalMap.headMap(key));
136   }
137 
138   public synchronized SoftValueSortedMap<K,V> tailMap(K key) {
139     checkReferences();
140     return new SoftValueSortedMap<K,V>(this.internalMap.tailMap(key));
141   }
142 
143   public synchronized SoftValueSortedMap<K,V> subMap(K fromKey, K toKey) {
144     checkReferences();
145     return new SoftValueSortedMap<K,V>(this.internalMap.subMap(fromKey, toKey));
146   }
147 
148   public synchronized boolean isEmpty() {
149     checkReferences();
150     return this.internalMap.isEmpty();
151   }
152 
153   public synchronized int size() {
154     checkReferences();
155     return this.internalMap.size();
156   }
157 
158   public synchronized void clear() {
159     checkReferences();
160     this.internalMap.clear();
161   }
162 
163   public synchronized Set<K> keySet() {
164     checkReferences();
165     return this.internalMap.keySet();
166   }
167 
168   @SuppressWarnings("unchecked")
169   public synchronized Comparator comparator() {
170     return this.internalMap.comparator();
171   }
172 
173   public synchronized Set<Map.Entry<K,V>> entrySet() {
174     checkReferences();
175     Set<Map.Entry<K, SoftValue<K,V>>> entries = this.internalMap.entrySet();
176     Set<Map.Entry<K, V>> real_entries = new TreeSet<Map.Entry<K,V>>();
177     for(Map.Entry<K, SoftValue<K,V>> entry : entries) {
178       real_entries.add(entry.getValue());
179     }
180     return real_entries;
181   }
182 
183   public synchronized Collection<V> values() {
184     checkReferences();
185     Collection<SoftValue<K,V>> softValues = this.internalMap.values();
186     ArrayList<V> hardValues = new ArrayList<V>();
187     for(SoftValue<K,V> softValue : softValues) {
188       hardValues.add(softValue.get());
189     }
190     return hardValues;
191   }
192 }