speedup: call force() only at the end of the build, between chunk builds drop only...
[idea/community.git] / jps / model / src / org / jetbrains / ether / dependencyView / PersistentMultiMaplet.java
1 /*
2  * Copyright 2000-2011 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.ether.dependencyView;
17
18 import com.intellij.util.io.DataExternalizer;
19 import com.intellij.util.io.KeyDescriptor;
20 import com.intellij.util.io.PersistentHashMap;
21
22 import java.io.*;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.LinkedList;
26 import java.util.Map;
27
28 /**
29  * Created by IntelliJ IDEA.
30  * User: db
31  * Date: 08.03.11
32  * Time: 15:38
33  * To change this template use File | Settings | File Templates.
34  */
35 class PersistentMultiMaplet<K, V> implements MultiMaplet<K, V> {
36   private final PersistentHashMap<K, Collection<V>> myMap;
37   private final DataExternalizer<V> myValueExternalizer;
38
39   public PersistentMultiMaplet(final File file,
40                                final KeyDescriptor<K> keyExternalizer,
41                                final DataExternalizer<V> valueExternalizer,
42                                final TransientMultiMaplet.CollectionConstructor<V> collectionFactory) throws IOException {
43     myValueExternalizer = valueExternalizer;
44     myMap = new PersistentHashMap<K, Collection<V>>(file, keyExternalizer,
45                                                     new CollectionDataExternalizer<V>(valueExternalizer, collectionFactory));
46   }
47
48
49   @Override
50   public boolean containsKey(final K key) {
51     try {
52       return myMap.containsMapping(key);
53     }
54     catch (IOException e) {
55       throw new RuntimeException(e);
56     }
57   }
58
59   @Override
60   public Collection<V> get(final K key) {
61     try {
62       return myMap.get(key);
63     }
64     catch (IOException e) {
65       throw new RuntimeException(e);
66     }
67   }
68
69   @Override
70   public void put(final K key, final Collection<V> value) {
71     try {
72       myMap.appendData(key, new PersistentHashMap.ValueDataAppender() {
73         public void append(DataOutput out) throws IOException {
74           for (V v : value) {
75             myValueExternalizer.save(out, v);
76           }
77         }
78       });
79     }
80     catch (IOException e) {
81       throw new RuntimeException(e);
82     }
83   }
84
85   @Override
86   public void put(final K key, final V value) {
87     put(key, Collections.singleton(value));
88   }
89
90   @Override
91   public void removeAll(K key, Collection<V> values) {
92     try {
93       final Collection<V> collection = myMap.get(key);
94
95       if (collection != null) {
96         if (collection.removeAll(values)) {
97           if (collection.isEmpty()) {
98             myMap.remove(key);
99           }
100           else {
101             myMap.put(key, collection);
102           }
103         }
104       }
105     }
106     catch (IOException e) {
107       throw new RuntimeException(e);
108     }
109   }
110
111   @Override
112   public void removeFrom(final K key, final V value) {
113     try {
114       final Collection<V> collection = myMap.get(key);
115
116       if (collection != null) {
117         if (collection.remove(value)) {
118           if (collection.isEmpty()) {
119             myMap.remove(key);
120           }
121           else {
122             myMap.put(key, collection);
123           }
124         }
125       }
126     }
127     catch (IOException e) {
128       throw new RuntimeException(e);
129     }
130   }
131
132   @Override
133   public void remove(final K key) {
134     try {
135       myMap.remove(key);
136     }
137     catch (IOException e) {
138       throw new RuntimeException(e);
139     }
140   }
141
142   @Override
143   public void putAll(MultiMaplet<K, V> m) {
144     for (Map.Entry<K, Collection<V>> entry : m.entrySet()) {
145       final K key = entry.getKey();
146       remove(key);
147       put(key, entry.getValue());
148     }
149   }
150
151   public Collection<K> keyCollection() {
152     try {
153       return myMap.getAllKeysWithExistingMapping();
154     }
155     catch (IOException e) {
156       throw new RuntimeException(e);
157     }
158   }
159
160   @Override
161   public void close() {
162     try {
163       myMap.close();
164     }
165     catch (IOException e) {
166       throw new RuntimeException(e);
167     }
168   }
169
170   public void flush(boolean memoryCachesOnly) {
171     if (memoryCachesOnly) {
172       myMap.dropMemoryCaches();
173     }
174     else {
175       myMap.force();
176     }
177   }
178
179   @Override
180   public Collection<Map.Entry<K, Collection<V>>> entrySet() {
181     final Collection<Map.Entry<K, Collection<V>>> result = new LinkedList<Map.Entry<K, Collection<V>>>();
182
183     try {
184       for (final K key : myMap.getAllKeysWithExistingMapping()) {
185         final Collection<V> value = myMap.get(key);
186
187         final Map.Entry<K, Collection<V>> entry = new Map.Entry<K, Collection<V>>() {
188           @Override
189           public K getKey() {
190             return key;
191           }
192
193           @Override
194           public Collection<V> getValue() {
195             return value;
196           }
197
198           @Override
199           public Collection<V> setValue(Collection<V> value) {
200             return null;
201           }
202         };
203
204         result.add(entry);
205       }
206
207       return result;
208     }
209     catch (IOException e) {
210       throw new RuntimeException(e);
211     }
212   }
213
214   private static class CollectionDataExternalizer<V> implements DataExternalizer<Collection<V>> {
215     private final DataExternalizer<V> myElementExternalizer;
216     private final TransientMultiMaplet.CollectionConstructor<V> myCollectionFactory;
217
218     public CollectionDataExternalizer(DataExternalizer<V> elementExternalizer,
219                                       TransientMultiMaplet.CollectionConstructor<V> collectionFactory) {
220       myElementExternalizer = elementExternalizer;
221       myCollectionFactory = collectionFactory;
222     }
223
224     @Override
225     public void save(final DataOutput out, final Collection<V> value) throws IOException {
226       for (V x : value) {
227         myElementExternalizer.save(out, x);
228       }
229     }
230
231     @Override
232     public Collection<V> read(final DataInput in) throws IOException {
233       final Collection<V> result = myCollectionFactory.create();
234       final DataInputStream stream = (DataInputStream)in;
235       while (stream.available() > 0) {
236         result.add(myElementExternalizer.read(in));
237       }
238       return result;
239     }
240   }
241 }