1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.indexing;
15 import java.io.FileFilter;
16 import java.io.IOException;
17 import java.util.ArrayList;
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;
34 * A facade for Simantics graph database index management facilities.
36 * @author Tuukka Lehtonen
38 public final class DatabaseIndexing {
40 private static final boolean DEBUG = IndexPolicy.TRACE_INDEX_MANAGEMENT;
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();
51 public static File getIndexLocation(Session session, Resource relation, Resource input) {
53 throw new NullPointerException("null session");
55 throw new NullPointerException("null relation");
57 throw new NullPointerException("null input");
59 String dir = session.getService(ServerInformation.class).getDatabaseId()
60 + "." + relation.getResourceId()
61 + "." + input.getResourceId();
63 return new File(getIndexBaseLocation(), dir);
66 private static File getAllDirtyFile() {
67 return new File(getIndexBaseLocation(), ".dirty");
70 private static File getChangedFile(File indexPath) {
71 return new File(indexPath, ".changed");
74 public static void markAllDirty() throws IOException {
75 File indexBase = getIndexBaseLocation();
76 if (!indexBase.exists() || !indexBase.isDirectory())
79 System.out.println("Marking all indexes dirty");
80 File allDirtyFile = getAllDirtyFile();
81 if (allDirtyFile.createNewFile()) {
82 FileUtils.syncFile(allDirtyFile);
86 public static void clearAllDirty() throws IOException {
88 System.out.println("Clearing dirty state of all indexes");
90 File indexBase = getIndexBaseLocation();
91 if (!indexBase.exists() || !indexBase.isDirectory())
94 forEachIndexPath(new Procedure<File, IOException>() {
96 public void execute(File indexPath) throws IOException {
97 getChangedFile(indexPath).delete();
101 getAllDirtyFile().delete();
105 * Internal to indexing, invoked by {@link IndexedRelationsImpl} which
106 * doesn't want to throw these exceptions forward. Just log it.
110 static void markIndexChanged(Session session, File indexPath) {
112 System.out.println("Marking index dirty: " + indexPath);
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);
123 } catch (IOException e) {
124 Logger.defaultLogError(e);
128 private static IndexChangedWriter getIndexChangedWriter(Session session) {
129 IndexChangedWriter writer = session.peekService(IndexChangedWriter.class);
130 if (writer == null) {
131 synchronized (IndexChangedWriter.class) {
133 session.registerService(IndexChangedWriter.class, writer = new IndexChangedWriter());
139 public static void deleteAllIndexes() throws IOException {
140 File indexBase = DatabaseIndexing.getIndexBaseLocation();
142 ArrayList<String> filter = new ArrayList<>(2);
143 filter.add(getAllDirtyFile().getAbsolutePath());
144 filter.add(indexBase.getAbsolutePath());
146 FileUtils.deleteAllWithFilter(indexBase, filter);
147 FileUtils.deleteAll(indexBase);
150 public static void deleteIndex(final Resource relation, final Resource modelPart) throws DatabaseException {
152 SimanticsInternal.getSession().syncRequest(new WriteRequest() {
155 public void perform(WriteGraph graph) throws DatabaseException {
156 deleteIndex(graph, relation, modelPart);
163 public static void deleteIndex(WriteGraph graph, final Resource relation, final Resource modelPart) throws DatabaseException {
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);
175 public static void deleteIndex(File indexPath) throws IOException {
177 System.out.println("Deleting index " + indexPath);
179 ArrayList<String> filter = new ArrayList<>(2);
180 filter.add(getChangedFile(indexPath).getAbsolutePath());
181 filter.add(indexPath.getAbsolutePath());
183 FileUtils.deleteAllWithFilter(indexPath, filter);
184 FileUtils.deleteAll(indexPath);
187 public static void validateIndexes() throws IOException {
188 File indexBase = getIndexBaseLocation();
190 System.out.println("Validating indexes at " + indexBase);
191 if (!indexBase.exists())
193 if (!indexBase.isDirectory()) {
194 // Make sure that index-base is a valid directory
196 System.out.println(indexBase + " is not a directory! Removing it.");
197 FileUtils.deleteAll(indexBase);
201 File allDirtyFile = getAllDirtyFile();
202 if (allDirtyFile.isFile()) {
204 System.out.println("All indexes marked dirty, removing them.");
207 forEachIndexPath(new Procedure<File, IOException>() {
209 public void execute(File indexPath) throws IOException {
210 File changed = getChangedFile(indexPath);
211 if (changed.isFile()) {
213 System.out.println("Index is dirty, removing: " + indexPath);
214 deleteIndex(indexPath);
221 interface Procedure<T, E extends Throwable> {
222 void execute(T t) throws E;
225 private static <E extends Throwable> void forEachIndexPath(Procedure<File, E> callback) throws E {
226 for (File indexPath : getIndexBaseLocation().listFiles(new FileFilter() {
228 public boolean accept(File pathname) {
229 return pathname.isDirectory();
232 callback.execute(indexPath);