]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.indexing/src/org/simantics/db/indexing/DatabaseIndexing.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.indexing / src / org / simantics / db / indexing / DatabaseIndexing.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.indexing;\r
13 \r
14 import java.io.File;\r
15 import java.io.FileFilter;\r
16 import java.io.IOException;\r
17 \r
18 import org.simantics.db.Resource;\r
19 import org.simantics.db.Session;\r
20 import org.simantics.db.WriteGraph;\r
21 import org.simantics.db.common.request.IndexRoot;\r
22 import org.simantics.db.common.request.WriteRequest;\r
23 import org.simantics.db.common.utils.Logger;\r
24 import org.simantics.db.exception.DatabaseException;\r
25 import org.simantics.db.layer0.adapter.GenericRelationIndex;\r
26 import org.simantics.db.layer0.genericrelation.IndexedRelations;\r
27 import org.simantics.db.layer0.internal.SimanticsInternal;\r
28 import org.simantics.db.service.ServerInformation;\r
29 import org.simantics.utils.FileUtils;\r
30 \r
31 /**\r
32  * A facade for Simantics graph database index management facilities.\r
33  * \r
34  * @author Tuukka Lehtonen\r
35  */\r
36 public final class DatabaseIndexing {\r
37 \r
38     private static final boolean DEBUG = IndexPolicy.TRACE_INDEX_MANAGEMENT;\r
39 \r
40     public static File getIndexBaseLocation() {\r
41         return Activator.getDefault().getIndexBaseFile();\r
42 //      Activator activator = Activator.getDefault();\r
43 //        Bundle b = Platform.getBundle(Activator.BUNDLE_ID);\r
44 //        IPath state = Platform.getStateLocation(b);\r
45 //        File path = state.append("index").toFile();\r
46 //        return path;\r
47     }\r
48 \r
49     public static File getIndexLocation(Session session, Resource relation, Resource input) {\r
50         if (session == null)\r
51             throw new NullPointerException("null session");\r
52         if (relation == null)\r
53             throw new NullPointerException("null relation");\r
54         if (input == null)\r
55             throw new NullPointerException("null input");\r
56 \r
57         String dir = session.getService(ServerInformation.class).getDatabaseId()\r
58         + "." + relation.getResourceId()\r
59         + "." + input.getResourceId();\r
60 \r
61         return new File(getIndexBaseLocation(), dir);\r
62     }\r
63 \r
64     private static File getAllDirtyFile() {\r
65         return new File(getIndexBaseLocation(), ".dirty");\r
66     }\r
67 \r
68     private static File getChangedFile(File indexPath) {\r
69         return new File(indexPath, ".changed");\r
70     }\r
71 \r
72     public static void markAllDirty() throws IOException {\r
73         File indexBase = getIndexBaseLocation();\r
74         if (!indexBase.exists() || !indexBase.isDirectory())\r
75             return;\r
76         if (DEBUG)\r
77             System.out.println("Marking all indexes dirty");\r
78         getAllDirtyFile().createNewFile();\r
79     }\r
80 \r
81     public static void clearAllDirty() throws IOException {\r
82         if (DEBUG)\r
83             System.out.println("Clearing dirty state of all indexes");\r
84 \r
85         File indexBase = getIndexBaseLocation();\r
86         if (!indexBase.exists() || !indexBase.isDirectory())\r
87             return;\r
88         delete(getAllDirtyFile());\r
89 \r
90         forEachIndexPath(new Procedure<File, IOException>() {\r
91             @Override\r
92             public void execute(File indexPath) throws IOException {\r
93                 delete(getChangedFile(indexPath));\r
94             }\r
95         });\r
96     }\r
97 \r
98     /**\r
99      * Internal to indexing, invoked by {@link IndexedRelationsImpl} which\r
100      * doesn't want to throw these exceptions forward. Just log it.\r
101      * \r
102      * @param indexPath\r
103      */\r
104     static void markIndexChanged(File indexPath) {\r
105         if (!indexPath.exists())\r
106             throw new IllegalArgumentException("index path " + indexPath + " does not exist");\r
107         if (!indexPath.isDirectory())\r
108             throw new IllegalArgumentException("index path " + indexPath + " is not a directory");\r
109         try {\r
110             if (DEBUG)\r
111                 System.out.println("Marking index dirty: " + indexPath);\r
112             getChangedFile(indexPath).createNewFile();\r
113         } catch (IOException e) {\r
114             Logger.defaultLogError(e);\r
115         }\r
116     }\r
117 \r
118     public static void deleteAllIndexes() throws IOException {\r
119         File indexBase = DatabaseIndexing.getIndexBaseLocation();\r
120         delete(indexBase);\r
121     }\r
122 \r
123     public static void deleteIndex(final Resource relation, final Resource modelPart) throws DatabaseException {\r
124 \r
125         SimanticsInternal.getSession().syncRequest(new WriteRequest() {\r
126 \r
127                         @Override\r
128                         public void perform(WriteGraph graph) throws DatabaseException {\r
129                                 deleteIndex(graph, relation, modelPart);\r
130                         }\r
131                 \r
132         });\r
133 \r
134     }\r
135 \r
136     public static void deleteIndex(WriteGraph graph, final Resource relation, final Resource modelPart) throws DatabaseException {\r
137         \r
138         Resource model = graph.syncRequest(new IndexRoot(modelPart));\r
139         GenericRelationIndex index = graph.adapt(relation, GenericRelationIndex.class);\r
140         IndexedRelations ir = graph.getService(IndexedRelations.class);\r
141         // Deletes index files\r
142         ir.reset(null, graph, relation, model);\r
143         // Notifies DB listeners\r
144         index.reset(graph, model);\r
145         \r
146     }\r
147     \r
148     public static void deleteIndex(File indexPath) throws IOException {\r
149         if (DEBUG)\r
150             System.out.println("Deleting index " + indexPath);\r
151         delete(indexPath);\r
152     }\r
153 \r
154     public static void validateIndexes() throws IOException {\r
155         File indexBase = getIndexBaseLocation();\r
156         if (DEBUG)\r
157             System.out.println("Validating indexes at " + indexBase);\r
158         if (!indexBase.exists())\r
159             return;\r
160         if (!indexBase.isDirectory()) {\r
161             // Make sure that index-base is a valid directory\r
162             if (DEBUG)\r
163                 System.out.println(indexBase + " is not a directory! Removing it.");\r
164             delete(indexBase);\r
165             indexBase.mkdirs();\r
166             return;\r
167         }\r
168         File allDirtyFile = getAllDirtyFile();\r
169         if (allDirtyFile.isFile()) {\r
170             if (DEBUG)\r
171                 System.out.println("All indexes marked dirty, removing them.");\r
172             delete(allDirtyFile);\r
173             deleteAllIndexes();\r
174         } else {\r
175             forEachIndexPath(new Procedure<File, IOException>() {\r
176                 @Override\r
177                 public void execute(File indexPath) throws IOException {\r
178                     File changed = getChangedFile(indexPath);\r
179                     if (changed.isFile()) {\r
180                         if (DEBUG)\r
181                             System.out.println("Index is dirty, removing: " + indexPath);\r
182                         deleteIndex(indexPath);\r
183                     }\r
184                 }\r
185             });\r
186         }\r
187     }\r
188 \r
189 \r
190     private static void delete(File fileOrDir) throws IOException {\r
191         if (fileOrDir.exists())\r
192             FileUtils.deleteAll(fileOrDir);\r
193     }\r
194 \r
195     interface Procedure<T, E extends Throwable> {\r
196         void execute(T t) throws E;\r
197     }\r
198 \r
199     private static <E extends Throwable> void forEachIndexPath(Procedure<File, E> callback) throws E {\r
200         for (File indexPath : getIndexBaseLocation().listFiles(new FileFilter() {\r
201             @Override\r
202             public boolean accept(File pathname) {\r
203                 return pathname.isDirectory();\r
204             }\r
205         })) {\r
206             callback.execute(indexPath);\r
207         }\r
208     }\r
209 \r
210 }\r