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
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.util
.io
.FileUtil
;
21 import com
.intellij
.openapi
.vfs
.VirtualFile
;
22 import com
.intellij
.util
.containers
.SLRUCache
;
23 import gnu
.trove
.TIntHashSet
;
24 import org
.jetbrains
.annotations
.NotNull
;
25 import org
.jetbrains
.annotations
.Nullable
;
30 * @author Eugene Zhuravlev
33 public class FileContentStorage
{
34 private static final Logger LOG
= Logger
.getInstance("#com.intellij.util.indexing.FileContentStorage");
35 private static final byte[] EMPTY_BYTE_ARRAY
= new byte[]{};
37 private int myKeyBeingRemoved
= -1;
38 private final File myStorageRoot
;
39 private final TIntHashSet myFileIds
= new TIntHashSet();
40 private final Object myLock
= new Object();
42 private final SLRUCache
<Integer
, byte[]> myCache
= new SLRUCache
<Integer
, byte[]>(256, 64) {
44 public byte[] createValue(final Integer key
) {
45 final int _keyValue
= key
.intValue();
46 if (myFileIds
.contains(_keyValue
)) {
47 final File dataFile
= getDataFile(_keyValue
);
49 return FileUtil
.loadFileBytes(dataFile
);
51 catch (IOException ignored
) {
54 return EMPTY_BYTE_ARRAY
;
57 protected void onDropFromCache(final Integer key
, final byte[] bytes
) {
58 if (key
.intValue() == myKeyBeingRemoved
) {
59 FileUtil
.delete(getDataFile(key
));
61 else if (bytes
.length
> 0){
62 final File dataFile
= getDataFile(key
);
64 final BufferedOutputStream os
= new BufferedOutputStream(new FileOutputStream(dataFile
));
72 catch (IOException e
) {
80 private File
getDataFile(final int fileId
) {
81 return new File(myStorageRoot
, String
.valueOf(fileId
));
84 public FileContentStorage(File storageRoot
) {
85 myStorageRoot
= storageRoot
;
86 final boolean wasCreated
= storageRoot
.mkdirs();
88 final String
[] names
= storageRoot
.list();
90 for (String name
: names
) {
92 myFileIds
.add(Integer
.parseInt(name
));
94 catch (NumberFormatException ignored
) {
101 public void offer(VirtualFile file
) throws IOException
{
103 final byte[] bytes
= file
.contentsToByteArray();
105 synchronized (myLock
) {
106 final int fileId
= Math
.abs(FileBasedIndex
.getFileId(file
));
107 final boolean added
= myFileIds
.add(fileId
);
109 myCache
.put(fileId
, bytes
);
114 catch (FileNotFoundException ignored
) {
115 // may happen, if content was never queried before
116 // In this case the index for this file must not have been built and it is ok to ignore the file
118 //catch (IOException e) {
124 public byte[] remove(VirtualFile file
) {
125 final int fileId
= Math
.abs(FileBasedIndex
.getFileId(file
));
126 synchronized (myLock
) {
128 return myFileIds
.contains(fileId
)? myCache
.get(fileId
) : null;
131 if (myFileIds
.remove(fileId
)) {
132 myKeyBeingRemoved
= fileId
;
133 if (!myCache
.remove(fileId
)) {
134 FileUtil
.delete(getDataFile(fileId
));
136 myKeyBeingRemoved
= -1;
142 public boolean containsContent(VirtualFile file
) {
143 final int fileId
= Math
.abs(FileBasedIndex
.getFileId(file
));
144 synchronized (myLock
) {
145 return myFileIds
.contains(fileId
);
149 public void dispose() {
150 myCache
.clear(); // drop contexts on disk if something is left in memory