1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.cache;
18
19 import java.util.Map;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ConcurrentMap;
22 import java.util.concurrent.locks.Lock;
23 import java.util.concurrent.locks.ReadWriteLock;
24 import java.util.concurrent.locks.ReentrantReadWriteLock;
25
26 import org.apache.commons.collections4.map.AbstractLinkedMap;
27 import org.apache.commons.collections4.map.LRUMap;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.commons.vfs2.FileName;
31 import org.apache.commons.vfs2.FileObject;
32 import org.apache.commons.vfs2.FileSystem;
33 import org.apache.commons.vfs2.FileSystemException;
34 import org.apache.commons.vfs2.VfsLog;
35 import org.apache.commons.vfs2.util.Messages;
36
37
38
39
40
41
42
43 public class LRUFilesCache extends AbstractFilesCache {
44
45
46 private static final int DEFAULT_LRU_SIZE = 100;
47
48
49 private static final Log log = LogFactory.getLog(LRUFilesCache.class);
50
51
52 private final ConcurrentMap<FileSystem, Map<FileName, FileObject>> filesystemCache = new ConcurrentHashMap<>(10);
53
54
55 private final int lruSize;
56
57 private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
58 private final Lock readLock = rwLock.readLock();
59 private final Lock writeLock = rwLock.writeLock();
60
61
62
63
64 private class MyLRUMap extends LRUMap<FileName, FileObject> {
65
66
67
68 private static final long serialVersionUID = 20101208L;
69
70
71 private final FileSystem filesystem;
72
73 public MyLRUMap(final FileSystem filesystem, final int size) {
74 super(size, true);
75 this.filesystem = filesystem;
76 }
77
78 @Override
79 protected boolean removeLRU(final AbstractLinkedMap.LinkEntry<FileName, FileObject> linkEntry) {
80 synchronized (LRUFilesCache.this) {
81 @SuppressWarnings("resource")
82 final FileObject fileObject = linkEntry.getValue();
83
84
85
86 if (fileObject.isAttached() || fileObject.isContentOpen()) {
87
88
89
90
91 return false;
92 }
93
94
95 if (super.removeLRU(linkEntry)) {
96 try {
97
98 fileObject.close();
99 } catch (final FileSystemException e) {
100 VfsLog.warn(getLogger(), log, Messages.getString("vfs.impl/LRUFilesCache-remove-ex.warn"), e);
101 }
102
103 final Map<?, ?> files = filesystemCache.get(filesystem);
104 if (files.isEmpty()) {
105 filesystemCache.remove(filesystem);
106 }
107
108 return true;
109 }
110
111 return false;
112 }
113 }
114 }
115
116
117
118
119 public LRUFilesCache() {
120 this(DEFAULT_LRU_SIZE);
121 }
122
123
124
125
126
127
128 public LRUFilesCache(final int lruSize) {
129 this.lruSize = lruSize;
130 }
131
132 @Override
133 public void putFile(final FileObject file) {
134 final Map<FileName, FileObject> files = getOrCreateFilesystemCache(file.getFileSystem());
135
136 writeLock.lock();
137 try {
138 files.put(file.getName(), file);
139 } finally {
140 writeLock.unlock();
141 }
142 }
143
144 @Override
145 public boolean putFileIfAbsent(final FileObject file) {
146 final Map<FileName, FileObject> files = getOrCreateFilesystemCache(file.getFileSystem());
147
148 writeLock.lock();
149 try {
150 final FileName name = file.getName();
151
152 if (files.containsKey(name)) {
153 return false;
154 }
155
156 files.put(name, file);
157 return true;
158 } finally {
159 writeLock.unlock();
160 }
161 }
162
163 @Override
164 public FileObject getFile(final FileSystem filesystem, final FileName name) {
165 final Map<FileName, FileObject> files = getOrCreateFilesystemCache(filesystem);
166
167 readLock.lock();
168 try {
169 return files.get(name);
170 } finally {
171 readLock.unlock();
172 }
173 }
174
175 @Override
176 public void clear(final FileSystem filesystem) {
177 final Map<FileName, FileObject> files = getOrCreateFilesystemCache(filesystem);
178
179 writeLock.lock();
180 try {
181 files.clear();
182
183 filesystemCache.remove(filesystem);
184 } finally {
185 writeLock.unlock();
186 }
187 }
188
189 protected Map<FileName, FileObject> getOrCreateFilesystemCache(final FileSystem filesystem) {
190 Map<FileName, FileObject> files = filesystemCache.get(filesystem);
191 if (files == null) {
192 files = new MyLRUMap(filesystem, lruSize);
193 filesystemCache.putIfAbsent(filesystem, files);
194 }
195 return files;
196 }
197
198 @Override
199 public void close() {
200 super.close();
201 filesystemCache.clear();
202 }
203
204 @Override
205 public void removeFile(final FileSystem filesystem, final FileName name) {
206 final Map<?, ?> files = getOrCreateFilesystemCache(filesystem);
207
208 writeLock.lock();
209 try {
210 files.remove(name);
211
212 if (files.isEmpty()) {
213 filesystemCache.remove(filesystem);
214 }
215 } finally {
216 writeLock.unlock();
217 }
218 }
219
220 @Override
221 public void touchFile(final FileObject file) {
222
223 getFile(file.getFileSystem(), file.getName());
224 }
225 }