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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.indexing;
\r
14 import java.io.File;
\r
15 import java.io.FileFilter;
\r
16 import java.io.IOException;
\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
32 * A facade for Simantics graph database index management facilities.
\r
34 * @author Tuukka Lehtonen
\r
36 public final class DatabaseIndexing {
\r
38 private static final boolean DEBUG = IndexPolicy.TRACE_INDEX_MANAGEMENT;
\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
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
55 throw new NullPointerException("null input");
\r
57 String dir = session.getService(ServerInformation.class).getDatabaseId()
\r
58 + "." + relation.getResourceId()
\r
59 + "." + input.getResourceId();
\r
61 return new File(getIndexBaseLocation(), dir);
\r
64 private static File getAllDirtyFile() {
\r
65 return new File(getIndexBaseLocation(), ".dirty");
\r
68 private static File getChangedFile(File indexPath) {
\r
69 return new File(indexPath, ".changed");
\r
72 public static void markAllDirty() throws IOException {
\r
73 File indexBase = getIndexBaseLocation();
\r
74 if (!indexBase.exists() || !indexBase.isDirectory())
\r
77 System.out.println("Marking all indexes dirty");
\r
78 getAllDirtyFile().createNewFile();
\r
81 public static void clearAllDirty() throws IOException {
\r
83 System.out.println("Clearing dirty state of all indexes");
\r
85 File indexBase = getIndexBaseLocation();
\r
86 if (!indexBase.exists() || !indexBase.isDirectory())
\r
88 delete(getAllDirtyFile());
\r
90 forEachIndexPath(new Procedure<File, IOException>() {
\r
92 public void execute(File indexPath) throws IOException {
\r
93 delete(getChangedFile(indexPath));
\r
99 * Internal to indexing, invoked by {@link IndexedRelationsImpl} which
\r
100 * doesn't want to throw these exceptions forward. Just log it.
\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
111 System.out.println("Marking index dirty: " + indexPath);
\r
112 getChangedFile(indexPath).createNewFile();
\r
113 } catch (IOException e) {
\r
114 Logger.defaultLogError(e);
\r
118 public static void deleteAllIndexes() throws IOException {
\r
119 File indexBase = DatabaseIndexing.getIndexBaseLocation();
\r
123 public static void deleteIndex(final Resource relation, final Resource modelPart) throws DatabaseException {
\r
125 SimanticsInternal.getSession().syncRequest(new WriteRequest() {
\r
128 public void perform(WriteGraph graph) throws DatabaseException {
\r
129 deleteIndex(graph, relation, modelPart);
\r
136 public static void deleteIndex(WriteGraph graph, final Resource relation, final Resource modelPart) throws DatabaseException {
\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
148 public static void deleteIndex(File indexPath) throws IOException {
\r
150 System.out.println("Deleting index " + indexPath);
\r
154 public static void validateIndexes() throws IOException {
\r
155 File indexBase = getIndexBaseLocation();
\r
157 System.out.println("Validating indexes at " + indexBase);
\r
158 if (!indexBase.exists())
\r
160 if (!indexBase.isDirectory()) {
\r
161 // Make sure that index-base is a valid directory
\r
163 System.out.println(indexBase + " is not a directory! Removing it.");
\r
165 indexBase.mkdirs();
\r
168 File allDirtyFile = getAllDirtyFile();
\r
169 if (allDirtyFile.isFile()) {
\r
171 System.out.println("All indexes marked dirty, removing them.");
\r
172 delete(allDirtyFile);
\r
173 deleteAllIndexes();
\r
175 forEachIndexPath(new Procedure<File, IOException>() {
\r
177 public void execute(File indexPath) throws IOException {
\r
178 File changed = getChangedFile(indexPath);
\r
179 if (changed.isFile()) {
\r
181 System.out.println("Index is dirty, removing: " + indexPath);
\r
182 deleteIndex(indexPath);
\r
190 private static void delete(File fileOrDir) throws IOException {
\r
191 if (fileOrDir.exists())
\r
192 FileUtils.deleteAll(fileOrDir);
\r
195 interface Procedure<T, E extends Throwable> {
\r
196 void execute(T t) throws E;
\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
202 public boolean accept(File pathname) {
\r
203 return pathname.isDirectory();
\r
206 callback.execute(indexPath);
\r