Source code: org/scoja/server/target/FileLRUCache.java
1
2 package org.scoja.server.target;
3
4 import org.scoja.util.LRUShell;
5 import org.scoja.util.ExpiringLRUCache;
6 import org.scoja.util.TransientMap;
7 import org.scoja.common.PriorityUtils;
8 import org.scoja.server.core.EventContext;
9 import org.scoja.server.source.Internal;
10
11 /**
12 * Es una caché de ficheros abiertos.
13 * Está implementada con un {@link ExpiringLRUCache}, así que hereda
14 * de ella tanto sus capacidades (control por tamaño y tiempo) como su
15 * idiosincrasia de uso (todos los accesos son a través del método
16 * {@link #get(String)}).
17 * <p><b>Forma de uso</b>
18 * Si <code>fileCache</code> contiene un FileLRUCache,
19 * <code><pre>
20 * final FileShell file = fileCache.get(filename, env);
21 if (file != null) {
22 try {
23 final OutputStream out = file.getOutputStream();
24 .....
25 } catch (IOException e) {
26 System.err.println("UGGS: " + e.getMessage());
27 } finally {
28 file.release();
29 }
30 }
31 * </pre></code>
32 * El método {@link #get(String)} devuelve <code>null</code> si no
33 * pudo abrir el fichero; además produce un evento interno con level
34 * {@link PriorityUtils#CRIT}; por tanto, no es necesario producir
35 * ningún mensaje en el sitio de uso.
36 * Para que un error de apertura no provoque una cantidad
37 * desproporcianada de mensajes de error y de intentos de apertura (lo
38 * que redudaría muy negativamente en el rendimiento de Scoja),
39 * se mantiene una tabla con los ficheros que han fallado.
40 */
41 public class FileLRUCache
42 implements TransientMap.Graveyard {
43
44 public static final int DEFAULT_OPEN_MAX_SIZE = 500;
45 public static final long DEFAULT_OPEN_MAX_INACTIVITY = 5*60*1000;
46 public static final int DEFAULT_FAILED_MAX_SIZE = 50000;
47 public static final long DEFAULT_FAILED_MAX_INACTIVITY = 5*60*1000;
48
49 protected final ExpiringLRUCache openCache;
50 protected final TransientMap failedCache;
51
52 public FileLRUCache() {
53 openCache = new ExpiringLRUCache(DEFAULT_OPEN_MAX_SIZE,
54 DEFAULT_OPEN_MAX_INACTIVITY);
55 failedCache = new TransientMap(DEFAULT_FAILED_MAX_INACTIVITY);
56 failedCache.setGraveyard(this);
57 }
58
59 public void setSize(final int maxSize) {
60 openCache.setSize(maxSize);
61 }
62
63 public void setInactivity(final long maxInactivity) {
64 openCache.setInactivity(maxInactivity);
65 }
66
67 public void setFailedMemory(final long maxMemory) {
68 failedCache.setFadingOut(maxMemory);
69 }
70
71 /**
72 * Busca el fichero <code>filename</code> en esta caché.
73 * Si no lo encuentra y recuerda haber fallado en esta operación
74 * hace poco, devuelve <code>null</code>.
75 * Si no lo encuentra y no recuerda haber fallado en esta
76 * operación hace poco, intenta abrirlo.
77 * Si falla en la operación de abrirlo, genera un mensaje
78 * {@link Internal#crit} y devuelve <code>null</code>.
79 * En cualquier otro caso, el resultado es distinto de
80 * <code>null</code> y ya contiene el fichero abierto.
81 * <b>No se debe olvidar hacer un <code>release()</code> sobre el
82 * resultado una vez que ya se ha terminado de usar.</b>
83 */
84 public FileShell get(final String filename,
85 final EventContext env) {
86 final LRUShell shell = openCache.get(filename);
87 FileShell file = (FileShell)shell.getValue();
88 if (file == null) {
89 final Object name = failedCache.get(filename);
90 if (name == null) {
91 try {
92 file = new FileShell(filename, shell);
93 Internal.notice(env, "File \"" +filename+ "\""
94 + " added to the open files cache");
95 shell.put(file);
96 } catch (Throwable e) {
97 shell.release();
98 failedCache.put(filename, filename);
99 Internal.crit(env, "Error " + e.getMessage()
100 + " while trying open file " + filename
101 + " to write " + env.getEvent());
102 }
103 } else {
104 if (PriorityUtils.DEBUG <= Internal.LOG_DETAIL) {
105 Internal.debug(env, "Ignoring request to open file \""
106 +filename+"\" because recently failed");
107 }
108 }
109 } else {
110 if (PriorityUtils.DEBUG <= Internal.LOG_DETAIL) {
111 Internal.debug(env, "File \"" +filename+ "\""
112 + " found in the open file cache");
113 }
114 }
115 return file;
116 }
117
118 public void died(final Object key, final Object value) {
119 Internal.notice("Forgetting that opening file \"" +key+ "\" failed."
120 + " I will try to open it at next request.");
121 }
122 }