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