OSDN Git Service

Move index scanning to separate thread to increase performance.
authorRandy Baumgarte <randy@fbn.cx>
Thu, 2 Dec 2010 01:23:12 +0000 (20:23 -0500)
committerRandy Baumgarte <randy@fbn.cx>
Wed, 15 Dec 2010 15:16:57 +0000 (10:16 -0500)
src/cx/fbn/nevernote/NeverNote.java
src/cx/fbn/nevernote/signals/IndexSignal.java [new file with mode: 0644]
src/cx/fbn/nevernote/sql/NoteResourceTable.java
src/cx/fbn/nevernote/threads/IndexRunner.java

index 8719090..1616200 100644 (file)
@@ -43,6 +43,8 @@ import java.util.List;
 import java.util.SortedMap;
 import java.util.Vector;
 
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
 import org.apache.thrift.TException;
 import org.h2.tools.ChangeFileEncryption;
 
@@ -304,7 +306,7 @@ public class NeverNote extends QMainWindow{
     boolean                            windowMaximized = false;        // Keep track of the window state for restores
     List<String>               pdfReadyQueue;                          // Queue of PDFs that are ready to be rendered.
     List<QPixmap>              syncIcons;
-    
+    private static Logger log = Logger.getLogger(NeverNote.class); 
     
     
     String iconPath = new String("classpath:cx/fbn/nevernote/icons/");
@@ -681,6 +683,7 @@ public class NeverNote extends QMainWindow{
        
        // Main entry point
        public static void main(String[] args) {
+               log.setLevel(Level.FATAL);
                QApplication.initialize(args);
                QPixmap pixmap = new QPixmap("classpath:cx/fbn/nevernote/icons/splash_logo.png");
                QSplashScreen splash = new QSplashScreen(pixmap);
@@ -975,9 +978,10 @@ public class NeverNote extends QMainWindow{
        }
        
        private void setupIndexListeners() {
-               indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
-               indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
-//                     indexRunner.threadSignal.indexNeeded.connect(listManager, "setIndexNeeded(String, String, Boolean)");
+//             indexRunner.noteSignal.noteIndexed.connect(this, "indexThreadComplete(String)");
+//             indexRunner.resourceSignal.resourceIndexed.connect(this, "indexThreadComplete(String)");
+               indexRunner.signal.indexStarted.connect(this, "indexStarted()");
+               indexRunner.signal.indexFinished.connect(this, "indexComplete()");
        }
        private void setupSyncSignalListeners() {
                syncRunner.tagSignal.listChanged.connect(this, "tagIndexUpdated()");
@@ -4059,31 +4063,16 @@ public class NeverNote extends QMainWindow{
     @SuppressWarnings("unused")
        private void fullReindex() {
        logger.log(logger.HIGH, "Entering NeverNote.fullReindex");
-       // If we are deleting non-trash notes
-       if (currentNote == null) return;
-       if (currentNote.getDeleted() == 0) { 
-               if (QMessageBox.question(this, tr("Confirmation"), tr("This will cause all notes & attachments to be reindexed, "+
-                               "but please be aware that depending upon the size of your database updating all these records " +
-                               "can be time consuming and NeverNote will be unresponsive until it is complete.  Do you wish to continue?"),
-                               QMessageBox.StandardButton.Yes, 
-                                       QMessageBox.StandardButton.No)==StandardButton.No.value() && Global.verifyDelete() == true) {
-                                                               return;
-               }
-       }
-       waitCursor(true);
-       setMessage(tr("Marking notes for reindex."));
-       conn.getNoteTable().reindexAllNotes();
-       conn.getNoteTable().noteResourceTable.reindexAll(); 
+       indexRunner.addWork("REINDEXALL");
        setMessage(tr("Database will be reindexed."));
-       waitCursor(false);
-       logger.log(logger.HIGH, "Leaving NeverNote.fullRefresh");
+       logger.log(logger.HIGH, "Leaving NeverNote.fullReindex");
     }
     // Listener when a user wants to reindex a specific note
     @SuppressWarnings("unused")
        private void reindexNote() {
        logger.log(logger.HIGH, "Entering NeverNote.reindexNote");
                for (int i=0; i<selectedNoteGUIDs.size(); i++) {
-                       conn.getNoteTable().setIndexNeeded(selectedNoteGUIDs.get(i), true);
+                       indexRunner.addWork("REINDEXNOTE "+selectedNoteGUIDs.get(i));
                }
                if (selectedNotebookGUIDs.size() > 1)
                        setMessage(tr("Notes will be reindexed."));
@@ -4779,6 +4768,7 @@ public class NeverNote extends QMainWindow{
                        syncRunner.syncDeletedContent = Global.synchronizeDeletedContent();
                        
                        if (syncThreadsReady > 0) {
+                               indexRunner.interrupt = true;
                                saveNoteIndexWidth();
                                saveNoteColumnPositions();
                                if (syncRunner.addWork("SYNC")) {
@@ -4882,66 +4872,17 @@ public class NeverNote extends QMainWindow{
                logger.log(logger.EXTREME, "Index timer activated.  Sync running="+syncRunning);
                if (syncRunning) 
                        return;
-               // Look for any unindexed notes.  We only refresh occasionally 
-               // and do one at a time to keep overhead down.
-               if (!indexDisabled && indexRunner.getWorkQueueSize() == 0) { 
-                       List<String> notes = conn.getNoteTable().getNextUnindexed(1);
-                       String unindexedNote = null;
-                       if (notes.size() > 0)
-                               unindexedNote = notes.get(0);
-                       if (unindexedNote != null && Global.keepRunning) {
-                               indexNoteContent(unindexedNote);
-                       }
-                       if (notes.size()>0) {
-                               indexTimer.setInterval(100);
-                               return;
-                       }
-                       List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getNextUnindexed(1);
-                       if (unindexedResources.size() > 0 && indexRunner.getWorkQueueSize() == 0) {
-                               String unindexedResource = unindexedResources.get(0);
-                               if (unindexedResource != null && Global.keepRunning) {
-                                       indexNoteResource(unindexedResource);
-                               }
-                       }
-                       if (unindexedResources.size() > 0) {
-                               indexTimer.setInterval(100);
-                               return;
-                       } else {
-                               indexTimer.setInterval(indexTime);
-                       }
-                       if (indexRunning) {
-                               setMessage(tr("Index completed."));
-                               logger.log(logger.LOW, "Indexing has completed.");
-                               indexRunning = false;
-                               indexTimer.setInterval(indexTime);
-                       }
+               if (!indexDisabled && indexRunner.idle) { 
+                       indexRunner.addWork("SCAN");
                }
                logger.log(logger.EXTREME, "Leaving neverNote index timer");
        }
-       private synchronized void indexNoteContent(String unindexedNote) {
-               logger.log(logger.EXTREME, "Entering NeverNote.indexNoteContent()");
-               logger.log(logger.MEDIUM, "Unindexed Note found: "+unindexedNote);
-               indexRunner.setIndexType(indexRunner.CONTENT);
-               indexRunner.addWork("CONTENT "+unindexedNote);
-               if (!indexRunning) {
-                       setMessage(tr("Indexing notes."));
-                       logger.log(logger.LOW, "Beginning to index note contents.");
-                       indexRunning = true;
-               }
-               logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteContent()");
-       }
-       private synchronized void indexNoteResource(String unindexedResource) {
-               logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteResource()");
-               indexRunner.addWork(new String("RESOURCE "+unindexedResource));
-               if (!indexRunning) {
-                       setMessage(tr("Indexing notes."));
-                       indexRunning = true;
-               }
-               logger.log(logger.EXTREME, "Leaving NeverNote.indexNoteResource()");
+
+       private void indexStarted() {
+               setMessage(tr("Indexing notes"));
        }
-       @SuppressWarnings("unused")
-       private void indexThreadComplete(String guid) {
-               logger.log(logger.MEDIUM, "Index complete for "+guid);
+       private void indexComplete() {
+               setMessage(tr("Index complete"));
        }
        @SuppressWarnings("unused")
        private synchronized void toggleNoteIndexing() {
diff --git a/src/cx/fbn/nevernote/signals/IndexSignal.java b/src/cx/fbn/nevernote/signals/IndexSignal.java
new file mode 100644 (file)
index 0000000..b1a480f
--- /dev/null
@@ -0,0 +1,29 @@
+/*\r
+ * This file is part of NeverNote \r
+ * Copyright 2009 Randy Baumgarte\r
+ * \r
+ * This file may be licensed under the terms of of the\r
+ * GNU General Public License Version 2 (the ``GPL'').\r
+ *\r
+ * Software distributed under the License is distributed\r
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
+ * express or implied. See the GPL for the specific language\r
+ * governing rights and limitations.\r
+ *\r
+ * You should have received a copy of the GPL along with this\r
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
+ * or write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+*/\r
+\r
+package cx.fbn.nevernote.signals;\r
+\r
+import com.trolltech.qt.QSignalEmitter;\r
+\r
+\r
+\r
+public class IndexSignal extends QSignalEmitter {\r
+       public Signal0 indexStarted = new Signal0();\r
+       public Signal0 indexFinished = new Signal0();\r
+}\r
index 6acc357..2c262cf 100644 (file)
@@ -108,6 +108,23 @@ public class NoteResourceTable  {
                }       \r
                return guids;   \r
        }\r
+       // get any unindexed resource\r
+       public List<String> getUnindexed() {\r
+               List<String> guids = new ArrayList<String>();\r
+        NSqlQuery query = new NSqlQuery(db.getConnection());\r
+                                       \r
+               if (!query.exec("Select guid from NoteResources where indexNeeded = true"))\r
+                       logger.log(logger.EXTREME, "NoteResources SQL retrieve has failed on getUnindexed(): " +query.lastError());\r
+\r
+               // Get a list of the notes\r
+               String guid;\r
+               while (query.next()) {\r
+                       guid = new String();\r
+                       guid = query.valueString(0);\r
+                       guids.add(guid);\r
+               }       \r
+               return guids;   \r
+       }\r
 \r
        public List<String> findInkNotes() {\r
                List<String> guids = new ArrayList<String>();\r
index c352c12..61158d4 100644 (file)
@@ -26,6 +26,7 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;\r
 import java.io.IOException;\r
 import java.io.InputStream;\r
+import java.util.List;\r
 import java.util.concurrent.LinkedBlockingQueue;\r
 \r
 import org.apache.commons.lang.StringEscapeUtils;\r
@@ -54,6 +55,7 @@ import com.trolltech.qt.xml.QDomElement;
 import com.trolltech.qt.xml.QDomNodeList;\r
 \r
 import cx.fbn.nevernote.Global;\r
+import cx.fbn.nevernote.signals.IndexSignal;\r
 import cx.fbn.nevernote.signals.NoteResourceSignal;\r
 import cx.fbn.nevernote.signals.NoteSignal;\r
 import cx.fbn.nevernote.sql.DatabaseConnection;\r
@@ -67,24 +69,24 @@ public class IndexRunner extends QObject implements Runnable {
        public volatile NoteSignal                      noteSignal;\r
        public volatile NoteResourceSignal      resourceSignal;\r
        private int                                                     indexType;\r
-       public final int                                        CONTENT=1; \r
-       public final int                                        RESOURCE=2;\r
+       public final int                                        SCAN=1; \r
+       public final int                                        REINDEXALL=2;\r
+       public final int                                        REINDEXNOTE=3;\r
        public boolean                                          keepRunning;\r
        private final QDomDocument                      doc;\r
        private static String                           regex = Global.getWordRegex();\r
        private final DatabaseConnection        conn;\r
        private volatile LinkedBlockingQueue<String> workQueue;\r
        private static int MAX_QUEUED_WAITING = 1000;\r
-\r
-       \r
+       public boolean interrupt;\r
+       public boolean idle;\r
+       public volatile IndexSignal                     signal;\r
 \r
        \r
        public IndexRunner(String logname, String u, String uid, String pswd, String cpswd) {\r
                logger = new ApplicationLogger(logname);\r
                conn = new DatabaseConnection(logger, u, uid, pswd, cpswd);\r
-               noteSignal = new NoteSignal();\r
-               resourceSignal = new NoteResourceSignal();\r
-               indexType = CONTENT;\r
+               indexType = SCAN;\r
                guid = null;\r
                keepRunning = true;\r
                doc = new QDomDocument();\r
@@ -99,39 +101,47 @@ public class IndexRunner extends QObject implements Runnable {
        @Override\r
        public void run() {\r
                thread().setPriority(Thread.MIN_PRIORITY);\r
+               noteSignal = new NoteSignal();\r
+               resourceSignal = new NoteResourceSignal();\r
+               signal = new IndexSignal();\r
                logger.log(logger.EXTREME, "Starting index thread ");\r
                while (keepRunning) {\r
+                       idle=true;\r
                        try {\r
                                String work = workQueue.take();\r
-                               if (work.startsWith("CONTENT")) {\r
-                                       work = work.replace("CONTENT ", "");\r
-                                       guid = work;\r
-                                       indexType = CONTENT;\r
+                               idle=false;\r
+                               if (work.startsWith("SCAN")) {\r
+                                       guid=null;\r
+                                       interrupt = false;\r
+                                       indexType = SCAN;\r
+                               }\r
+                               if (work.startsWith("REINDEXALL")) {\r
+                                       guid = null;\r
+                                       indexType=REINDEXALL;\r
                                }\r
-                               if (work.startsWith("RESOURCE")) {\r
-                                       work = work.replace("RESOURCE ", "");\r
+                               if (work.startsWith("REINDEXNOTE")) {\r
+                                       work = work.replace("REINDEXNOTE ", "");\r
                                        guid = work;\r
-                                       indexType = RESOURCE;\r
+                                       indexType = REINDEXNOTE;\r
                                }\r
                                if (work.startsWith("STOP")) {\r
                                        keepRunning = false;\r
-                                       guid = work;\r
-                               }\r
-                               if (guid == null || guid.trim().equals("")) {\r
-                                       setIndexType(0);\r
-                                       resourceSignal.resourceIndexed.emit("null or empty guid");\r
+                                       guid = null;\r
                                }\r
                                logger.log(logger.EXTREME, "Type:" +indexType);\r
-                               if (indexType == CONTENT && keepRunning) {\r
-                                       logger.log(logger.MEDIUM, "Indexing note: "+guid);\r
-                                       indexNoteContent();\r
+                               if (indexType == SCAN && keepRunning) {\r
+                                       logger.log(logger.MEDIUM, "Scanning for unindexed notes & resources");\r
+                                       scanUnindexed();\r
                                        setIndexType(0);\r
                                }\r
-                               if (indexType == RESOURCE && keepRunning) {\r
-                                       logger.log(logger.MEDIUM, "Indexing resource: "+guid);\r
-                                       indexResource();\r
+                               if (indexType == REINDEXALL && keepRunning) {\r
+                                       logger.log(logger.MEDIUM, "Marking all for reindex");\r
+                                       reindexAll();\r
                                        setIndexType(0);\r
                                }\r
+                               if (indexType == REINDEXNOTE && keepRunning) {\r
+                                       reindexNote();\r
+                               }\r
                        } catch (InterruptedException e) {\r
                                // TODO Auto-generated catch block\r
                                e.printStackTrace();\r
@@ -142,6 +152,9 @@ public class IndexRunner extends QObject implements Runnable {
        \r
        // Reindex a note\r
        public void indexNoteContent() {\r
+               \r
+//             if (wordMap.size() > 0)\r
+//                     wordMap.clear();\r
                logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()");\r
                \r
                logger.log(logger.EXTREME, "Getting note content");\r
@@ -151,9 +164,6 @@ public class IndexRunner extends QObject implements Runnable {
                logger.log(logger.EXTREME, "Removing any encrypted data");\r
                data = removeEnCrypt(data);\r
                logger.log(logger.EXTREME, "Removing xml markups");\r
-               // These HTML characters need to be replaced by a space, or they'll cause words to jam together\r
-//             data = data.toLowerCase().replace("<br>", " ").replace("<hr>", " ").replace("<p>", " ").replace("<href>", " ");\r
-//             String text = StringEscapeUtils.unescapeHtml(data.replaceAll("\\<.*?\\>", ""));\r
                Tidy tidy = new Tidy();\r
                tidy.getStderr().close();  // the listener will capture messages\r
                tidy.setXmlTags(true);\r
@@ -269,6 +279,7 @@ public class IndexRunner extends QObject implements Runnable {
 \r
 \r
        private void indexResourceRTF(Resource r) {\r
+\r
                QTemporaryFile f = writeResource(r.getData());\r
                if (!keepRunning) {\r
                        return;\r
@@ -303,11 +314,14 @@ public class IndexRunner extends QObject implements Runnable {
                } catch (TikaException e) {\r
                        // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
                }\r
        }\r
 \r
        \r
        private void indexResourceODF(Resource r) {\r
+\r
                QTemporaryFile f = writeResource(r.getData());\r
                if (!keepRunning) {\r
                        return;\r
@@ -342,11 +356,14 @@ public class IndexRunner extends QObject implements Runnable {
                } catch (TikaException e) {\r
                        // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
                }\r
        }\r
 \r
        \r
        private void indexResourceOffice(Resource r) {\r
+\r
                QTemporaryFile f = writeResource(r.getData());\r
                if (!keepRunning) {\r
                        return;\r
@@ -381,19 +398,22 @@ public class IndexRunner extends QObject implements Runnable {
                } catch (TikaException e) {\r
                        // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
                }\r
        }\r
 \r
        \r
        \r
        private void indexResourcePDF(Resource r) {\r
+\r
                QTemporaryFile f = writeResource(r.getData());\r
                if (!keepRunning) {\r
                        return;\r
                }\r
                \r
                InputStream input;\r
-               try {\r
+               try {                   \r
                        input = new FileInputStream(new File(f.fileName()));\r
                        ContentHandler textHandler = new BodyContentHandler(-1);\r
                        Metadata metadata = new Metadata();\r
@@ -417,13 +437,14 @@ public class IndexRunner extends QObject implements Runnable {
                        e.printStackTrace();\r
                } catch (TikaException e) {\r
                        e.printStackTrace();\r
-//             } catch (Exception e) {\r
-//                     e.printStackTrace();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
                }\r
        }\r
        \r
        \r
        private void indexResourceOOXML(Resource r) {\r
+\r
                QTemporaryFile f = writeResource(r.getData());\r
                if (!keepRunning) {\r
                        return;\r
@@ -458,6 +479,8 @@ public class IndexRunner extends QObject implements Runnable {
                } catch (TikaException e) {\r
                        // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
                }\r
        }\r
        \r
@@ -501,7 +524,7 @@ public class IndexRunner extends QObject implements Runnable {
                        }\r
                        // Things have been trimmed off the end, so reverse the string & repeat.\r
                        buffer = buffer.reverse();\r
-                       for (int x = buffer.length()-1; x>=0; x--) {\r
+                       for (int x = buffer.length()-1; x>=0 && keepRunning; x--) {\r
                                if (!Character.isLetterOrDigit(buffer.charAt(x)))\r
                                        buffer = buffer.deleteCharAt(x);\r
                                else\r
@@ -510,13 +533,52 @@ public class IndexRunner extends QObject implements Runnable {
                        // Restore the string back to the proper order.\r
                        buffer = buffer.reverse();\r
                \r
-                       logger.log(logger.EXTREME, "Processing " +buffer);\r
                        if (buffer.length()>=Global.minimumWordCount) {\r
-                               logger.log(logger.EXTREME, "Adding " +buffer);\r
                                conn.getWordsTable().addWordToNoteIndex(guid, buffer.toString(), type, 100);\r
                        }\r
                }\r
+               return;\r
+       }\r
+       \r
+       private void scanUnindexed() {\r
+               List<String> notes = conn.getNoteTable().getUnindexed();\r
+               guid = null;\r
+               boolean started = false;\r
+               if (notes.size() > 0) {\r
+                       signal.indexStarted.emit();\r
+                       started = true;\r
+               }\r
+               for (int i=0; i<notes.size() && !interrupt && keepRunning; i++) {\r
+                       guid = notes.get(i);\r
+                       if (guid != null && keepRunning) {\r
+                               indexNoteContent();\r
+                       }\r
+               }\r
+               \r
+               List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed();\r
+               if (notes.size() > 0 && !started) {\r
+                       signal.indexStarted.emit();\r
+                       started = true;\r
+               }\r
+               for (int i=0; i>unindexedResources.size()&& !interrupt && keepRunning; i++) {\r
+                       guid = unindexedResources.get(i);\r
+                       if (keepRunning) {\r
+                               indexResource();\r
+                       }\r
+               }\r
+               if (started && keepRunning && !interrupt) \r
+                       signal.indexFinished.emit();\r
        }\r
        \r
+       private void reindexNote() {\r
+               if (guid == null)\r
+                       return;\r
+               conn.getNoteTable().setIndexNeeded(guid, true);\r
+       }\r
+       \r
+       private void reindexAll() {\r
+               conn.getNoteTable().reindexAllNotes();\r
+               conn.getNoteTable().noteResourceTable.reindexAll(); \r
+       }\r
 \r
 }\r