1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.util; |
7 | |
8 | import java.lang.ref.PhantomReference; |
9 | import java.lang.ref.Reference; |
10 | import java.lang.ref.ReferenceQueue; |
11 | import java.util.HashMap; |
12 | |
13 | import org.h2.engine.SysProperties; |
14 | import org.h2.message.DbException; |
15 | import org.h2.store.fs.FileUtils; |
16 | |
17 | /** |
18 | * This class deletes temporary files when they are not used any longer. |
19 | */ |
20 | public class TempFileDeleter { |
21 | |
22 | private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); |
23 | private final HashMap<PhantomReference<?>, String> refMap = New.hashMap(); |
24 | |
25 | private TempFileDeleter() { |
26 | // utility class |
27 | } |
28 | |
29 | public static TempFileDeleter getInstance() { |
30 | return new TempFileDeleter(); |
31 | } |
32 | |
33 | /** |
34 | * Add a file to the list of temp files to delete. The file is deleted once |
35 | * the file object is garbage collected. |
36 | * |
37 | * @param fileName the file name |
38 | * @param file the object to monitor |
39 | * @return the reference that can be used to stop deleting the file |
40 | */ |
41 | public synchronized Reference<?> addFile(String fileName, Object file) { |
42 | IOUtils.trace("TempFileDeleter.addFile", fileName, file); |
43 | PhantomReference<?> ref = new PhantomReference<Object>(file, queue); |
44 | refMap.put(ref, fileName); |
45 | deleteUnused(); |
46 | return ref; |
47 | } |
48 | |
49 | /** |
50 | * Delete the given file now. This will remove the reference from the list. |
51 | * |
52 | * @param ref the reference as returned by addFile |
53 | * @param fileName the file name |
54 | */ |
55 | public synchronized void deleteFile(Reference<?> ref, String fileName) { |
56 | if (ref != null) { |
57 | String f2 = refMap.remove(ref); |
58 | if (f2 != null) { |
59 | if (SysProperties.CHECK) { |
60 | if (fileName != null && !f2.equals(fileName)) { |
61 | DbException.throwInternalError("f2:" + f2 + " f:" + fileName); |
62 | } |
63 | } |
64 | fileName = f2; |
65 | } |
66 | } |
67 | if (fileName != null && FileUtils.exists(fileName)) { |
68 | try { |
69 | IOUtils.trace("TempFileDeleter.deleteFile", fileName, null); |
70 | FileUtils.tryDelete(fileName); |
71 | } catch (Exception e) { |
72 | // TODO log such errors? |
73 | } |
74 | } |
75 | } |
76 | |
77 | /** |
78 | * Delete all registered temp files. |
79 | */ |
80 | public void deleteAll() { |
81 | for (String tempFile : New.arrayList(refMap.values())) { |
82 | deleteFile(null, tempFile); |
83 | } |
84 | deleteUnused(); |
85 | } |
86 | |
87 | /** |
88 | * Delete all unused files now. |
89 | */ |
90 | public void deleteUnused() { |
91 | while (queue != null) { |
92 | Reference<? extends Object> ref = queue.poll(); |
93 | if (ref == null) { |
94 | break; |
95 | } |
96 | deleteFile(ref, null); |
97 | } |
98 | } |
99 | |
100 | /** |
101 | * This method is called if a file should no longer be deleted if the object |
102 | * is garbage collected. |
103 | * |
104 | * @param ref the reference as returned by addFile |
105 | * @param fileName the file name |
106 | */ |
107 | public void stopAutoDelete(Reference<?> ref, String fileName) { |
108 | IOUtils.trace("TempFileDeleter.stopAutoDelete", fileName, ref); |
109 | if (ref != null) { |
110 | String f2 = refMap.remove(ref); |
111 | if (SysProperties.CHECK) { |
112 | if (f2 == null || !f2.equals(fileName)) { |
113 | DbException.throwInternalError("f2:" + f2 + |
114 | " " + (f2 == null ? "" : f2) + " f:" + fileName); |
115 | } |
116 | } |
117 | } |
118 | deleteUnused(); |
119 | } |
120 | |
121 | } |