--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.db.indexing;\r
+\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.apache.lucene.index.CorruptIndexException;\r
+import org.apache.lucene.queryparser.classic.ParseException;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.simantics.db.RequestProcessor;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.GenericRelation;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ * @author Antti Villberg\r
+ */\r
+public class IndexedRelationsSearcher extends IndexedRelationsSearcherBase {\r
+ \r
+ IndexedRelationsMemorySearcher cache;\r
+\r
+ IndexedRelationsSearcher(RequestProcessor session, Resource relation, Resource input, GenericRelation r) throws DatabaseException {\r
+ super(session, relation, input);\r
+ this.cache = new IndexedRelationsMemorySearcher(session, this, relation, input, r);\r
+ }\r
+\r
+ @Override\r
+ String getDescriptor() {\r
+ return "DISK: ";\r
+ }\r
+\r
+ @Override\r
+ public void setProblem(Throwable t) {\r
+ super.setProblem(t);\r
+ cache.setProblem(t);\r
+ }\r
+ \r
+ @Override\r
+ boolean startAccess(IProgressMonitor monitor, Session session, boolean forWriting) {\r
+ boolean success = super.startAccess(monitor, session, false);\r
+ if(!success) return false;\r
+ success = cache.startAccess(monitor, session, forWriting);\r
+ if(!success) {\r
+ setProblem(cache.getException());\r
+ return false;\r
+ } else return true;\r
+ }\r
+ \r
+ @Override\r
+ void insertIndex(IProgressMonitor monitor, GenericRelation r, int boundLength, Collection<Object[]> documentsData)\r
+ throws CorruptIndexException, IOException, DatabaseException {\r
+\r
+ Collection<Object> keyValues = new ArrayList<Object>();\r
+ for(Object[] data : documentsData) {\r
+ keyValues.add(data[1]);\r
+ }\r
+ \r
+ cache.replaceIndex(monitor, "Resource", keyValues, r, boundLength, documentsData);\r
+ //cache.commit();\r
+ \r
+ }\r
+ \r
+ @Override\r
+ void removeIndex(IProgressMonitor monitor, GenericRelation r, RequestProcessor processor, String key, Collection<Object> keyValues) throws DatabaseException,CorruptIndexException, IOException {\r
+ \r
+ Collection<Object[]> documentsData = new ArrayList<Object[]>();\r
+\r
+ Pair<String,String>[] fields = r.getFields(); \r
+\r
+ for(Object keyValue : keyValues) {\r
+ Object[] data = new Object[fields.length-1];\r
+ int index = 0;\r
+ for(int i=1;i<fields.length;i++) {\r
+ String fieldName = fields[i].first;\r
+ if(key.equals(fieldName)) {\r
+ data[index++] = keyValue;\r
+ } else {\r
+ String fieldClass = fields[i].second;\r
+ if ("Long".equals(fieldClass)) {\r
+ data[index++] = 0L;\r
+ } else if ("String".equals(fieldClass) || "Text".equals(fieldClass)) {\r
+ data[index++] = "";\r
+ } else {\r
+ throw new DatabaseException("Can only index Long and String fields, encountered class " + fieldClass);\r
+ }\r
+ }\r
+ }\r
+ documentsData.add(data);\r
+ }\r
+\r
+ cache.replaceIndex(monitor, key, keyValues, r, 1, documentsData);\r
+// cache.commit();\r
+ \r
+ }\r
+ \r
+ @Override\r
+ boolean replaceIndex(IProgressMonitor monitor, String key, Collection<Object> keyValues, GenericRelation r,\r
+ int boundLength, Collection<Object[]> documentsData) throws CorruptIndexException, IOException,\r
+ DatabaseException {\r
+\r
+ boolean result = cache.replaceIndex(monitor, key, keyValues, r, boundLength, documentsData);\r
+// cache.commit();\r
+ return result; \r
+ \r
+ }\r
+ \r
+ List<Map<String, Object>> persistentCachedSearch(IProgressMonitor monitor, RequestProcessor processor, String search,\r
+ int maxResultCount) throws ParseException, IOException, DatabaseException {\r
+ \r
+ MemoryIndexing mem = MemoryIndexing.getInstance(session.getSession());\r
+ \r
+ String key = indexPath.getAbsolutePath();\r
+ \r
+ Map<String,List<Map<String, Object>>> cache = mem.persistentCache.get(key);\r
+ if(cache != null) {\r
+ List<Map<String,Object>> result = cache.get(search);\r
+ if(result != null) return result;\r
+ }\r
+\r
+ startAccess(monitor, processor.getSession(), false);\r
+\r
+ List<Map<String, Object>> results = super.doSearch(monitor, processor, search, maxResultCount);\r
+ if(cache == null) {\r
+ cache = new HashMap<String,List<Map<String,Object>>>();\r
+ mem.persistentCache.put(key, cache);\r
+ }\r
+\r
+ if(results.size() < 500)\r
+ cache.put(search, results);\r
+ \r
+ return results;\r
+ \r
+ }\r
+\r
+ List<Resource> persistentCachedSearchResources(IProgressMonitor monitor, RequestProcessor processor, String search,\r
+ int maxResultCount) throws ParseException, IOException, DatabaseException {\r
+ \r
+ MemoryIndexing mem = MemoryIndexing.getInstance(session.getSession());\r
+ \r
+ String key = indexPath.getAbsolutePath();\r
+ \r
+ Map<String,List<Resource>> cache = mem.persistentCacheResources.get(key);\r
+ if(cache != null) {\r
+ List<Resource> result = cache.get(search);\r
+ if(result != null) return result;\r
+ }\r
+\r
+ startAccess(monitor, processor.getSession(), false);\r
+\r
+ List<Resource> results = super.doSearchResources(monitor, processor, search, maxResultCount);\r
+ if(cache == null) {\r
+ cache = new HashMap<String,List<Resource>>();\r
+ mem.persistentCacheResources.put(key, cache);\r
+ }\r
+\r
+ if(results.size() < 500)\r
+ cache.put(search, results);\r
+ \r
+ return results;\r
+ \r
+ }\r
+ \r
+ List<Object> persistentCachedList(IProgressMonitor monitor, RequestProcessor processor) throws ParseException, IOException, DatabaseException {\r
+ \r
+ startAccess(monitor, processor.getSession(), false);\r
+\r
+ List<Object> results = super.doList(monitor, processor);\r
+ \r
+ return results;\r
+ \r
+ }\r
+ \r
+ @Override\r
+ List<Map<String, Object>> doSearch(IProgressMonitor monitor, RequestProcessor processor, String search,\r
+ int maxResultCount) throws ParseException, IOException, DatabaseException {\r
+ \r
+ List<Map<String,Object>> persistent = persistentCachedSearch(monitor, processor, search, maxResultCount);\r
+ List<Map<String,Object>> cached = cache.doSearch(monitor, processor, search, maxResultCount);\r
+\r
+ ArrayList<Map<String,Object>> result = new ArrayList<Map<String,Object>>();\r
+\r
+ for(Map<String,Object> m : persistent) {\r
+ Resource r = (Resource)m.get("Resource");\r
+ if(!cache.changed.contains(r.getResourceId())) {\r
+ result.add(m);\r
+ }\r
+ }\r
+ result.addAll(cached);\r
+ return result;\r
+ \r
+ }\r
+ \r
+ @Override\r
+ List<Resource> doSearchResources(IProgressMonitor monitor, RequestProcessor processor, String search,\r
+ int maxResultCount) throws ParseException, IOException, DatabaseException {\r
+\r
+ List<Resource> persistent = persistentCachedSearchResources(monitor, processor, search, maxResultCount);\r
+ List<Resource> cached = cache.doSearchResources(monitor, processor, search, maxResultCount);\r
+\r
+ ArrayList<Resource> result = new ArrayList<Resource>();\r
+ for(Resource r : persistent) {\r
+ if(!cache.changed.contains(r.getResourceId())) {\r
+ result.add(r);\r
+ }\r
+ }\r
+ result.addAll(cached);\r
+ return result;\r
+ \r
+ }\r
+ \r
+ List<Object> doList(IProgressMonitor monitor, RequestProcessor processor) throws ParseException, IOException, DatabaseException {\r
+\r
+ List<Object> persistent = persistentCachedList(monitor, processor);\r
+ \r
+ // TODO: check that caches have been properly flushed\r
+ //List<Object> cached = cache.doList(monitor, processor);\r
+ //if(!cached.isEmpty()) throw new DatabaseException("doList does not support caching");\r
+\r
+ return persistent;\r
+ \r
+ }\r
+\r
+ void applyChanges(IProgressMonitor monitor, Session session, GenericRelation r, Collection<Object[]> os) throws Exception {\r
+ \r
+ if(!os.isEmpty()) {\r
+ \r
+ ArrayList<Object> replaceKeys = new ArrayList<Object>();\r
+ ArrayList<Object[]> replaceValues = new ArrayList<Object[]>();\r
+ ArrayList<Object> removeKeys = new ArrayList<Object>();\r
+ for(Object[] o : os) {\r
+ Long parent = (Long)o[0];\r
+ Long key = (Long)o[1];\r
+ if(parent != 0) {\r
+ replaceKeys.add(key);\r
+ replaceValues.add(o);\r
+ } else {\r
+ removeKeys.add(key);\r
+ }\r
+ }\r
+ \r
+ changeState(monitor, session, State.READY);\r
+ \r
+ super.startAccess(null, session, true);\r
+ \r
+ super.replaceIndex(null, "Resource", replaceKeys, r, 1, replaceValues);\r
+ super.removeIndex(null, r, null, "Resource", removeKeys);\r
+ \r
+ }\r
+ \r
+ changeState(monitor, session, State.READY);\r
+ \r
+ }\r
+ \r
+ @Override\r
+ Throwable bestEffortClear(IProgressMonitor monitor, Session session) {\r
+\r
+ // Free the index\r
+ changeState(monitor, session, State.NONE);\r
+ \r
+ Throwable t = clearDirectory(monitor, session);\r
+ if(t != null) return t;\r
+\r
+ t = cache.bestEffortClear(monitor, session);\r
+ if(t != null) return t;\r
+ \r
+ String key = indexPath.getAbsolutePath();\r
+ MemoryIndexing mem = MemoryIndexing.getInstance(session);\r
+ mem.persistentCache.remove(key);\r
+ mem.persistentCacheResources.remove(key);\r
+ \r
+ return null;\r
+ \r
+ }\r
+ \r
+}\r