2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.intellij
.util
.indexing
;
19 import com
.intellij
.util
.CommonProcessors
;
20 import com
.intellij
.util
.Processor
;
21 import com
.intellij
.util
.containers
.ContainerUtil
;
22 import org
.jetbrains
.annotations
.NotNull
;
24 import java
.io
.IOException
;
26 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
29 * This storage is needed for indexing yet unsaved data without saving those changes to 'main' backend storage
31 * @author Eugene Zhuravlev
34 public class MemoryIndexStorage
<Key
, Value
> implements IndexStorage
<Key
, Value
> {
35 private final Map
<Key
, UpdatableValueContainer
<Value
>> myMap
= new HashMap
<Key
,UpdatableValueContainer
<Value
>>();
36 private final IndexStorage
<Key
, Value
> myBackendStorage
;
37 private final List
<BufferingStateListener
> myListeners
= ContainerUtil
.createEmptyCOWList();
38 private final AtomicBoolean myBufferingEnabled
= new AtomicBoolean(false);
40 public interface BufferingStateListener
{
41 void bufferingStateChanged(boolean newState
);
42 void memoryStorageCleared();
45 public MemoryIndexStorage(IndexStorage
<Key
, Value
> backend
) {
46 myBackendStorage
= backend
;
49 public void addBufferingStateListsner(BufferingStateListener listener
) {
50 myListeners
.add(listener
);
53 public void removeBufferingStateListsner(BufferingStateListener listener
) {
54 myListeners
.remove(listener
);
57 public void setBufferingEnabled(boolean enabled
) {
58 final boolean wasEnabled
= myBufferingEnabled
.getAndSet(enabled
);
59 if (wasEnabled
!= enabled
) {
60 for (BufferingStateListener listener
: myListeners
) {
61 listener
.bufferingStateChanged(enabled
);
66 public void clearMemoryMap() {
70 public void fireMemoryStorageCleared() {
71 for (BufferingStateListener listener
: myListeners
) {
72 listener
.memoryStorageCleared();
76 public void close() throws StorageException
{
77 myBackendStorage
.close();
80 public void clear() throws StorageException
{
82 myBackendStorage
.clear();
85 public void flush() throws IOException
{
86 myBackendStorage
.flush();
89 public Collection
<Key
> getKeys() throws StorageException
{
90 final Set
<Key
> keys
= new HashSet
<Key
>();
91 processKeys(new CommonProcessors
.CollectProcessor
<Key
>(keys
));
95 public boolean processKeys(final Processor
<Key
> processor
) throws StorageException
{
96 final Set
<Key
> stopList
= new HashSet
<Key
>();
98 Processor
<Key
> decoratingProcessor
= new Processor
<Key
>() {
99 public boolean process(final Key key
) {
100 if (stopList
.contains(key
)) return true;
102 final UpdatableValueContainer
<Value
> container
= myMap
.get(key
);
103 if (container
!= null && container
.size() == 0) return true;
104 return processor
.process(key
);
108 for (Key key
: myMap
.keySet()) {
109 if (!decoratingProcessor
.process(key
)) return false;
112 return myBackendStorage
.processKeys(decoratingProcessor
);
115 public void addValue(final Key key
, final int inputId
, final Value value
) throws StorageException
{
116 if (myBufferingEnabled
.get()) {
117 getMemValueContainer(key
).addValue(inputId
, value
);
120 final UpdatableValueContainer
<Value
> valueContainer
= myMap
.get(key
);
121 if (valueContainer
!= null) {
122 valueContainer
.addValue(inputId
, value
);
125 myBackendStorage
.addValue(key
, inputId
, value
);
128 public void removeValue(final Key key
, final int inputId
, final Value value
) throws StorageException
{
129 if (myBufferingEnabled
.get()) {
130 getMemValueContainer(key
).removeValue(inputId
, value
);
133 final UpdatableValueContainer
<Value
> valueContainer
= myMap
.get(key
);
134 if (valueContainer
!= null) {
135 valueContainer
.removeValue(inputId
, value
);
137 myBackendStorage
.removeValue(key
, inputId
, value
);
140 public void removeAllValues(Key key
, int inputId
) throws StorageException
{
141 if (myBufferingEnabled
.get()) {
142 getMemValueContainer(key
).removeAllValues(inputId
);
145 final UpdatableValueContainer
<Value
> valueContainer
= myMap
.get(key
);
146 if (valueContainer
!= null) {
147 valueContainer
.removeAllValues(inputId
);
150 myBackendStorage
.removeAllValues(key
, inputId
);
153 private UpdatableValueContainer
<Value
> getMemValueContainer(final Key key
) {
154 UpdatableValueContainer
<Value
> valueContainer
= myMap
.get(key
);
155 if (valueContainer
== null) {
156 valueContainer
= new ChangeTrackingValueContainer
<Value
>(new ChangeTrackingValueContainer
.Initializer
<Value
>() {
157 public Object
getLock() {
161 public ValueContainer
<Value
> compute() {
163 return myBackendStorage
.read(key
);
165 catch (StorageException e
) {
166 throw new RuntimeException(e
);
170 myMap
.put(key
, valueContainer
);
172 return valueContainer
;
176 public ValueContainer
<Value
> read(final Key key
) throws StorageException
{
177 final ValueContainer
<Value
> valueContainer
= myMap
.get(key
);
178 if (valueContainer
!= null) {
179 return valueContainer
;
182 return myBackendStorage
.read(key
);