beagle r4765 - in trunk/beagle: BeagleClient beagled



Author: dbera
Date: Sat May 31 23:25:07 2008
New Revision: 4765
URL: http://svn.gnome.org/viewvc/beagle?rev=4765&view=rev

Log:
Initial support for removable index:
* Add infrastructure for unloading a staticqueryable. Unloading a static queryable means
 1. Remove it from QueryDriver's list
 2. Close text-cache connection, fileattributestore_sqlite connection
 3. Close lucene.net.store.{primary, secondary}directory
* Add BeagleClient API to mount/unmount a removable index by giving its path
* Add a simple tool beagle-removable-index with --mount/--unmount <path>

TODO: Create a wrapper around BuildIndex which will support storing paths relative to the mount point and storing indexes in a different location (e.g. to build a catalogue of all CDs).


Added:
   trunk/beagle/BeagleClient/RemovableIndexControl.cs   (contents, props changed)
   trunk/beagle/beagled/RemovableIndexTool.cs   (contents, props changed)
Modified:
   trunk/beagle/BeagleClient/AssemblyInfo.cs
   trunk/beagle/BeagleClient/Makefile.am
   trunk/beagle/beagled/AssemblyInfo.cs
   trunk/beagle/beagled/FileAttributesStore.cs
   trunk/beagle/beagled/FileAttributesStore_ExtendedAttribute.cs
   trunk/beagle/beagled/FileAttributesStore_Mixed.cs
   trunk/beagle/beagled/FileAttributesStore_Sqlite.cs
   trunk/beagle/beagled/IFileAttributesStore.cs
   trunk/beagle/beagled/Makefile.am
   trunk/beagle/beagled/QueryDriver.cs
   trunk/beagle/beagled/RemoteControlExecutors.cs
   trunk/beagle/beagled/StaticQueryable.cs
   trunk/beagle/beagled/TextCache.cs

Modified: trunk/beagle/BeagleClient/AssemblyInfo.cs
==============================================================================
--- trunk/beagle/BeagleClient/AssemblyInfo.cs	(original)
+++ trunk/beagle/BeagleClient/AssemblyInfo.cs	Sat May 31 23:25:07 2008
@@ -36,26 +36,28 @@
 	 typeof (InformationalMessagesRequest),
 	 typeof (OptimizeIndexesRequest),
 	 typeof (Query),
-	 typeof (ReloadConfigRequest),
-	 typeof (ShutdownRequest),
 #if ENABLE_RDF_ADAPTER
 	 typeof (RDFQuery),
 #endif
+	 typeof (ReloadConfigRequest),
+	 typeof (RemovableIndexRequest),
+	 typeof (ShutdownRequest),
 	 typeof (SnippetRequest)
 )]
 	 
 [assembly: ResponseMessageTypes (
+	 typeof (CountMatchQueryResponse),
+	 typeof (DaemonInformationResponse),
 	 typeof (EmptyResponse),
 	 typeof (ErrorResponse),
 	 typeof (FinishedResponse),
 	 typeof (HitsAddedResponse),
 	 typeof (HitsSubtractedResponse),
 	 typeof (IndexingStatusResponse),
-	 typeof (SearchTermResponse),
-	 typeof (DaemonInformationResponse),
-	 typeof (SnippetResponse),
 #if ENABLE_RDF_ADAPTER
 	 typeof (RDFQueryResult),
 #endif
-	 typeof (CountMatchQueryResponse)
+	 typeof (RemovableIndexResponse),
+	 typeof (SearchTermResponse),
+	 typeof (SnippetResponse)
 )]

Modified: trunk/beagle/BeagleClient/Makefile.am
==============================================================================
--- trunk/beagle/BeagleClient/Makefile.am	(original)
+++ trunk/beagle/BeagleClient/Makefile.am	Sat May 31 23:25:07 2008
@@ -25,6 +25,7 @@
 	$(srcdir)/QueryResponses.cs            		\
 	$(srcdir)/QueryableStatus.cs			\
 	$(srcdir)/RemoteControl.cs			\
+	$(srcdir)/RemovableIndexControl.cs		\
 	$(srcdir)/Snippet.cs				\
 	$(srcdir)/Transport.cs				\
 	$(srcdir)/UnixTransport.cs			\

Added: trunk/beagle/BeagleClient/RemovableIndexControl.cs
==============================================================================
--- (empty file)
+++ trunk/beagle/BeagleClient/RemovableIndexControl.cs	Sat May 31 23:25:07 2008
@@ -0,0 +1,53 @@
+//
+// RemovableIndexControl.cs
+//
+// Copyright (C) 2008 D Bera <dbera web gmail com>
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections;
+using System.Text;
+using System.Xml;
+using System.Xml.Serialization;
+
+using Beagle.Util;
+
+namespace Beagle {
+
+	public class RemovableIndexRequest : RequestMessage {
+		// To Mount or Unmount
+		public bool Mount;
+
+		// FIXME: More configurable ?
+		// 1. path to the config file
+		// 2. path to the index
+		// 3. path where the removable index is mounted
+		// Separate #3 is needed in case users want to search unmounted media
+		public string Path;
+	}
+
+	public class RemovableIndexResponse : ResponseMessage {
+		// If success, return the name of Static source.
+		// Otherwise return null.
+		public string Source;
+	}
+}

Modified: trunk/beagle/beagled/AssemblyInfo.cs
==============================================================================
--- trunk/beagle/beagled/AssemblyInfo.cs	(original)
+++ trunk/beagle/beagled/AssemblyInfo.cs	Sat May 31 23:25:07 2008
@@ -45,17 +45,18 @@
 
 // Executors go in here.
 [assembly: RequestMessageExecutorTypes (
+	typeof (CountMatchQueryExecutor),
 	typeof (DaemonInformationExecutor),
 	typeof (InformationalMessagesRequestExecutor),
 	typeof (OptimizeIndexesExecutor),
 	typeof (QueryExecutor),
-	typeof (ReloadConfigExecutor),
-	typeof (ShutdownExecutor),
-	typeof (SnippetExecutor),
 #if ENABLE_RDF_ADAPTER
 	typeof (RDFQueryExecutor),
 #endif
-	typeof (CountMatchQueryExecutor)
+	typeof (ReloadConfigExecutor),
+	typeof (RemovableIndexExecutor),
+	typeof (ShutdownExecutor),
+	typeof (SnippetExecutor)
 )]
 
 // All backends in this assembly must be registered here.

Modified: trunk/beagle/beagled/FileAttributesStore.cs
==============================================================================
--- trunk/beagle/beagled/FileAttributesStore.cs	(original)
+++ trunk/beagle/beagled/FileAttributesStore.cs	Sat May 31 23:25:07 2008
@@ -30,7 +30,7 @@
 
 namespace Beagle.Daemon {
 
-	public class FileAttributesStore {
+	public class FileAttributesStore : IDisposable {
 		
 		private static bool Debug = false;
 
@@ -41,6 +41,11 @@
 			this.ifas = ifas;
 		}
 
+		public void Dispose ()
+		{
+			ifas.Dispose ();
+		}
+
 		public FileAttributes Read (string path)
 		{
 			lock (ifas) {

Modified: trunk/beagle/beagled/FileAttributesStore_ExtendedAttribute.cs
==============================================================================
--- trunk/beagle/beagled/FileAttributesStore_ExtendedAttribute.cs	(original)
+++ trunk/beagle/beagled/FileAttributesStore_ExtendedAttribute.cs	Sat May 31 23:25:07 2008
@@ -49,6 +49,8 @@
 			this.index_fingerprint = index_fingerprint;
 		}
 
+		public void Dispose () { }
+
 		public FileAttributes Read (string path)
 		{
 			if (Disable)

Modified: trunk/beagle/beagled/FileAttributesStore_Mixed.cs
==============================================================================
--- trunk/beagle/beagled/FileAttributesStore_Mixed.cs	(original)
+++ trunk/beagle/beagled/FileAttributesStore_Mixed.cs	Sat May 31 23:25:07 2008
@@ -40,6 +40,12 @@
 			store_sqlite = new FileAttributesStore_Sqlite (directory, index_fingerprint);
 		}
 
+		public void Dispose ()
+		{
+			store_ea.Dispose ();
+			store_sqlite.Dispose ();
+		}
+
 		// We always have to query the Sqlite store first, because of our
 		// EA nightmare scenario: a file whose permissions or ownership get
 		// changed after the EAs have been attached.  Thus attributes in

Modified: trunk/beagle/beagled/FileAttributesStore_Sqlite.cs
==============================================================================
--- trunk/beagle/beagled/FileAttributesStore_Sqlite.cs	(original)
+++ trunk/beagle/beagled/FileAttributesStore_Sqlite.cs	Sat May 31 23:25:07 2008
@@ -194,6 +194,15 @@
 			DeleteCommand.CommandText = "DELETE FROM file_attributes WHERE directory= directory AND filename= filename";
 		}
 
+		public void Dispose ()
+		{
+			ReadCommand.Dispose ();
+			InsertCommand.Dispose ();
+			DeleteCommand.Dispose ();
+			connection.Dispose ();
+			connection = null;
+		}
+
 		///////////////////////////////////////////////////////////////////
 
 		private string GetDbPath (string directory)

Modified: trunk/beagle/beagled/IFileAttributesStore.cs
==============================================================================
--- trunk/beagle/beagled/IFileAttributesStore.cs	(original)
+++ trunk/beagle/beagled/IFileAttributesStore.cs	Sat May 31 23:25:07 2008
@@ -28,7 +28,7 @@
 
 namespace Beagle.Daemon {
 
-	public interface IFileAttributesStore {
+	public interface IFileAttributesStore : IDisposable {
 
 		FileAttributes Read  (string path);
 

Modified: trunk/beagle/beagled/Makefile.am
==============================================================================
--- trunk/beagle/beagled/Makefile.am	(original)
+++ trunk/beagle/beagled/Makefile.am	Sat May 31 23:25:07 2008
@@ -701,6 +701,31 @@
 
 ############################################################
 
+REMOVABLE_INDEX_WRAPPER = beagle-removable-index
+REMOVABLE_INDEX_TARGET = RemovableIndex.exe
+
+$(REMOVABLE_INDEX_WRAPPER): $(srcdir)/$(WRAPPER_IN)
+	$(WRAPPER_SED) -e "s|\ target\@|$(REMOVABLE_INDEX_TARGET)|g" < $(srcdir)/$(WRAPPER_IN) > $@
+	chmod +x $(REMOVABLE_INDEX_WRAPPER)
+
+REMOVABLE_INDEX_CSFLAGS = \
+	-target:exe
+
+REMOVABLE_INDEX_CSFILES = \
+	$(srcdir)/RemovableIndexTool.cs
+
+REMOVABLE_INDEX_LOCAL_ASSEMBLIES = 		\
+	../Util/Util.dll			\
+	../BeagleClient/Beagle.dll
+
+REMOVABLE_INDEX_ASSEMBLIES = \
+	$(REMOVABLE_INDEX_LOCAL_ASSEMBLIES:%=-r:%)
+
+$(REMOVABLE_INDEX_TARGET): $(REMOVABLE_INDEX_CSFILES) $(REMOVABLE_INDEX_LOCAL_ASSEMBLIES)
+	$(CSC) -out:$@ $(REMOVABLE_INDEX_CSFLAGS) $(REMOVABLE_INDEX_CSFILES) $(REMOVABLE_INDEX_ASSEMBLIES)
+
+############################################################
+
 CRAWL_SYSTEM_IN = beagle-crawl-system.in
 CRAWL_SYSTEM = beagle-crawl-system
 
@@ -734,6 +759,8 @@
 	$(MANAGE_INDEX_WRAPPER)		\
 	$(MASTER_DELETE_TARGET)		\
 	$(MASTER_DELETE_WRAPPER)	\
+	$(REMOVABLE_INDEX_TARGET)	\
+	$(REMOVABLE_INDEX_WRAPPER)	\
 	$(WEBINTERFACE_INDEX_XML)
 
 if ENABLE_THUNDERBIRD
@@ -802,6 +829,8 @@
 	$(INSTALL_DATA) $(DUMP_INDEX_TARGET).mdb         $(DESTDIR)$(pkglibdir)
 	$(INSTALL_DATA) $(MANAGE_INDEX_TARGET)           $(DESTDIR)$(pkglibdir)
 	$(INSTALL_DATA) $(MANAGE_INDEX_TARGET).mdb       $(DESTDIR)$(pkglibdir)
+	$(INSTALL_DATA) $(REMOVABLE_INDEX_TARGET)            $(DESTDIR)$(pkglibdir)
+	$(INSTALL_DATA) $(REMOVABLE_INDEX_TARGET).mdb        $(DESTDIR)$(pkglibdir)
 if ENABLE_THUNDERBIRD
 	$(INSTALL_DATA) $(THUNDERBIRD_TARGET)                 $(DESTDIR)$(BACKENDDIR)
 	$(INSTALL_DATA) $(THUNDERBIRD_TARGET).mdb             $(DESTDIR)$(BACKENDDIR)
@@ -852,6 +881,8 @@
 	rm -f $(DESTDIR)$(pkglibdir)/$(DUMP_INDEX_TARGET).mdb
 	rm -f $(DESTDIR)$(pkglibdir)/$(MANAGE_INDEX_TARGET)
 	rm -f $(DESTDIR)$(pkglibdir)/$(MANAGE_INDEX_TARGET).mdb
+	rm -f $(DESTDIR)$(pkglibdir)/$(REMOVABLE_INDEX_TARGET)
+	rm -f $(DESTDIR)$(pkglibdir)/$(REMOVABLE_INDEX_TARGET).mdb
 
 BIN_WRAPPERS = \
 	$(DAEMON_WRAPPER)		\
@@ -861,7 +892,8 @@
 	$(BUILD_INDEX_WRAPPER)		\
 	$(DUMP_INDEX_WRAPPER)		\
 	$(MANAGE_INDEX_WRAPPER)		\
-	$(MASTER_DELETE_WRAPPER)
+	$(MASTER_DELETE_WRAPPER)	\
+	$(REMOVABLE_INDEX_WRAPPER)
 
 noinst_SCRIPTS=	\
 	$(SNIPPET_TEST_WRAPPER)
@@ -888,7 +920,8 @@
 	$(INDEX_HELPER_CSFILES)			\
 	$(MASTER_DELETE_CSFILES)		\
 	$(MANAGE_INDEX_CSFILES)			\
-	$(BUILD_INDEX_CSFILES)
+	$(BUILD_INDEX_CSFILES)			\
+	$(REMOVABLE_INDEX_CSFILES)
 
 CLEANFILES = \
 	$(PLUGIN_TARGET)       			\
@@ -921,6 +954,9 @@
 	$(BUILD_INDEX_TARGET)			\
 	$(BUILD_INDEX_TARGET).mdb		\
 	$(BUILD_INDEX_WRAPPER)			\
+	$(REMOVABLE_INDEX_TARGET)			\
+	$(REMOVABLE_INDEX_TARGET).mdb		\
+	$(REMOVABLE_INDEX_WRAPPER)			\
 	$(THUNDERBIRD_TARGET)			\
 	$(THUNDERBIRD_TARGET).mdb		\
 	$(GOOGLE_BACKEND_TARGET)		\

Modified: trunk/beagle/beagled/QueryDriver.cs
==============================================================================
--- trunk/beagle/beagled/QueryDriver.cs	(original)
+++ trunk/beagle/beagled/QueryDriver.cs	Sat May 31 23:25:07 2008
@@ -138,6 +138,10 @@
 		// Use introspection to find all classes that implement IQueryable, the construct
 		// associated Queryables objects.
 
+		// To protect the list of iqueryables, since now we support adding/removing of
+		// static queryables at runtime
+		static ReaderWriterLock iqueryable_lock = new ReaderWriterLock ();
+
 		static Hashtable iqueryable_to_queryable = new Hashtable ();
 		static ICollection Queryables {
 			get { return iqueryable_to_queryable.Values; }
@@ -200,7 +204,7 @@
 				if (! UseQueryable (index_dir.Name))
 					continue;
 				
-				if (LoadStaticQueryable (index_dir, QueryDomain.System))
+				if (LoadStaticQueryable (index_dir, QueryDomain.System) != null)
 					count++;
 			}
 
@@ -229,33 +233,35 @@
 					continue;
 				
 				// FIXME: QueryDomain might be other than local
-				if (LoadStaticQueryable (index_dir, QueryDomain.Local))
+				if (LoadStaticQueryable (index_dir, QueryDomain.Local) != null)
 					count++;
 			}
 
 			Logger.Log.Info ("Found {0} user-configured static indexes..", count);
+
+			static_queryables = null;
 		}
 
 		// Instantiates and loads a StaticQueryable from an index directory
-		static private bool LoadStaticQueryable (DirectoryInfo index_dir, QueryDomain query_domain) 
+		static private Queryable LoadStaticQueryable (DirectoryInfo index_dir, QueryDomain query_domain) 
 		{
 			StaticQueryable static_queryable = null;
 			
 			if (!index_dir.Exists)
-				return false;
+				return null;
 			
 			try {
 				static_queryable = new StaticQueryable (index_dir.Name, index_dir.FullName, true);
 			} catch (InvalidOperationException) {
 				Logger.Log.Warn ("Unable to create read-only index (likely due to index version mismatch): {0}", index_dir.FullName);
-				return false;
+				return null;
 			} catch (Exception e) {
 				Logger.Log.Error (e, "Caught exception while instantiating static queryable: {0}", index_dir.Name);
-				return false;
+				return null;
 			}
 
 			if (static_queryable == null)
-				return false;
+				return null;
 
 			// Load StaticIndex.xml from index_dir.FullName/config
 			string config_file_path = Path.Combine (index_dir.FullName, "StaticIndex.xml");
@@ -264,17 +270,17 @@
 				static_index_config = Conf.LoadFrom (config_file_path);
 				if (static_index_config == null) {
 					Log.Error ("Unable to read config from {0}", config_file_path);
-					return false;
+					return null;
 				}
 			} catch (Exception e) {
 				Log.Error (e, "Caught exception while reading config from {0}", config_file_path);
-				return false;
+				return null;
 			}
 
 			string source = static_index_config.GetOption ("Source", null);
 			if (source == null) {
 				Log.Error ("Invalid config file: {0}", config_file_path);
-				return false;
+				return null;
 			}
 
 			QueryableFlavor flavor = new QueryableFlavor ();
@@ -284,7 +290,7 @@
 			Queryable queryable = new Queryable (flavor, static_queryable);
 			iqueryable_to_queryable [static_queryable] = queryable;
 
-			return true;
+			return queryable;
 		}
 
 		////////////////////////////////////////////////////////
@@ -602,13 +608,19 @@
 
 			if (! result.WorkerStart (dummy_worker))
 				return;
-			
-			foreach (Queryable queryable in Queryables)
-				DoOneQuery (queryable, query, result, null);
+
+			try {
+				iqueryable_lock.AcquireReaderLock (System.Threading.Timeout.Infinite);
+
+				foreach (Queryable queryable in Queryables)
+					DoOneQuery (queryable, query, result, null);
+			} finally {
+				iqueryable_lock.ReleaseReaderLock ();
+			}
 			
 			result.WorkerFinished (dummy_worker);
 		}
-		
+
 		static public void DoQueryLocal (Query       query,
 						 QueryResult result)
 		{
@@ -639,14 +651,20 @@
 		{
 			ArrayList all_results = new ArrayList ();
 
-			foreach (Queryable q in Queryables) {
-				if (! q.AcceptQuery (query))
-					continue;
+			try {
+				iqueryable_lock.AcquireReaderLock (System.Threading.Timeout.Infinite);
 
-				ICollection results = q.DoRDFQuery (query);
-				if (results == null || results.Count == 0)
-					continue;
-				all_results.AddRange (results);
+				foreach (Queryable q in Queryables) {
+					if (! q.AcceptQuery (query))
+						continue;
+
+					ICollection results = q.DoRDFQuery (query);
+					if (results == null || results.Count == 0)
+						continue;
+					all_results.AddRange (results);
+				}
+			} finally {
+				iqueryable_lock.ReleaseReaderLock ();
 			}
 
 			return all_results;
@@ -661,11 +679,17 @@
 
 			int num_matches = 0;
 
-			foreach (Queryable q in Queryables) {
-				if (! q.AcceptQuery (query))
-					continue;
+			try {
+				iqueryable_lock.AcquireReaderLock (System.Threading.Timeout.Infinite);
 
-				num_matches += q.DoCountMatchQuery (query);
+				foreach (Queryable q in Queryables) {
+					if (! q.AcceptQuery (query))
+						continue;
+
+					num_matches += q.DoCountMatchQuery (query);
+				}
+			} finally {
+				iqueryable_lock.ReleaseReaderLock ();
 			}
 
 			return num_matches;
@@ -675,8 +699,14 @@
 
 		static public IEnumerable GetIndexInformation ()
 		{
-			foreach (Queryable q in Queryables)
-				yield return q.GetQueryableStatus ();
+			try {
+				iqueryable_lock.AcquireReaderLock (System.Threading.Timeout.Infinite);
+
+				foreach (Queryable q in Queryables)
+					yield return q.GetQueryableStatus ();
+			} finally {
+				iqueryable_lock.ReleaseReaderLock ();
+			}
 		}
 
 		////////////////////////////////////////////////////////
@@ -689,18 +719,117 @@
 				if (! queryables_started)
 					return true;
 
-				foreach (Queryable q in Queryables) {
-					QueryableStatus status = q.GetQueryableStatus ();
+				try {
+					iqueryable_lock.AcquireReaderLock (System.Threading.Timeout.Infinite);
 
-					if (status == null)
-						return false;
+					foreach (Queryable q in Queryables) {
+						QueryableStatus status = q.GetQueryableStatus ();
 
-					if (status.IsIndexing)
-						return true;
+						if (status == null)
+							return false;
+
+						if (status.IsIndexing)
+							return true;
+					}
+
+					return false;
+				} finally {
+					iqueryable_lock.ReleaseReaderLock ();
 				}
+			}
+		}
+
+		/////////////////////////////////////////////////////////
+
+		// Removable Index related stuff
+
+		private static Dictionary<string, Queryable> removable_queryables = new Dictionary<string, Queryable> (4); // small number
+
+		internal static ResponseMessage HandleRemovableIndexRequest (string path, bool to_mount)
+		{
+			lock (removable_queryables) {
+				if (to_mount)
+					return AddRemovableIndex (path);
+				else
+					return RemoveRemovableIndex (path);
+			}
+		}
+
+		private static ResponseMessage AddRemovableIndex (string path)
+		{
+			DirectoryInfo index_dir = new DirectoryInfo (StringFu.SanitizePath (path));
+			if (! index_dir.Exists) {
+				ErrorResponse msg;
+				msg = new ErrorResponse ();
+				msg.ErrorMessage = "Adding removable index failed";
+				msg.Details = String.Format ("'{0}' does not exist.", path);
+				return msg;
+			}
+
+			if (removable_queryables.ContainsKey (path)) {
+				ErrorResponse msg;
+				msg = new ErrorResponse ();
+				msg.ErrorMessage = "Adding removable index failed";
+				msg.Details = String.Format ("'{0}' already added.", path);
+				return msg;
+			}
+
+			Queryable removable_queryable = null;
+
+			try {
+				iqueryable_lock.AcquireWriterLock (System.Threading.Timeout.Infinite);
+				removable_queryable = LoadStaticQueryable (index_dir, QueryDomain.Local);
+			} finally {
+				iqueryable_lock.ReleaseWriterLock ();
+			}
+
+			if (removable_queryable == null)
+				return new ErrorResponse ("Adding removable index failed");
 
-				return false;
+			removable_queryables [path] = removable_queryable;
+
+			RemovableIndexResponse resp = new RemovableIndexResponse ();
+			resp.Source = removable_queryable.Name;
+			Log.Info ("Adding removable index '{0}' from {1}", resp.Source, path);
+			return resp;
+		}
+
+		private static ResponseMessage RemoveRemovableIndex (string path)
+		{
+			if (! removable_queryables.ContainsKey (path)) {
+				ErrorResponse msg;
+				msg = new ErrorResponse ();
+				msg.ErrorMessage = "Removing removable-index failed";
+				msg.Details = String.Format ("'{0}' was not added.", path);
+				return msg;
 			}
+
+			Queryable removable_queryable = removable_queryables [path];
+
+			// Assert
+			if (removable_queryable == null ||
+			    ! (removable_queryable.IQueryable is StaticQueryable)) {
+				ErrorResponse msg = new ErrorResponse ("Removing removable-index failed");
+				return msg;
+			}
+
+			StaticQueryable static_queryable = (StaticQueryable) removable_queryable.IQueryable;
+			static_queryable.Close ();
+
+			removable_queryables.Remove (path);
+
+			try {
+				iqueryable_lock.AcquireWriterLock (System.Threading.Timeout.Infinite);
+				iqueryable_to_queryable [removable_queryable.IQueryable] = null;
+				iqueryable_to_queryable.Remove (removable_queryable.IQueryable);
+			} finally {
+				iqueryable_lock.ReleaseWriterLock ();
+			}
+
+			RemovableIndexResponse resp = new RemovableIndexResponse ();
+			resp.Source = removable_queryable.Name;
+			Log.Info ("Removed removable-index '{0}' at {1}", removable_queryable.Name, path);
+			return resp;
 		}
 
 		/////////////////////////////////////////////////////////
@@ -711,6 +840,7 @@
 		{
 			Log.Debug ("Debughook called:");
 			LuceneQueryable l;
+
 			foreach (Queryable q in Queryables) {
 				l = q.IQueryable as LuceneQueryable;
 				if (l == null)

Modified: trunk/beagle/beagled/RemoteControlExecutors.cs
==============================================================================
--- trunk/beagle/beagled/RemoteControlExecutors.cs	(original)
+++ trunk/beagle/beagled/RemoteControlExecutors.cs	Sat May 31 23:25:07 2008
@@ -99,4 +99,16 @@
 			return new EmptyResponse ();
 		}
 	}
+
+	[RequestMessage (typeof (RemovableIndexRequest))]
+	public class RemovableIndexExecutor : RequestMessageExecutor {
+		public override ResponseMessage Execute (RequestMessage req)
+		{
+			RemovableIndexRequest r = (RemovableIndexRequest) req;
+			string path = r.Path;
+			bool to_mount = r.Mount;
+
+			return QueryDriver.HandleRemovableIndexRequest (path, to_mount);
+		}
+	}
 }

Added: trunk/beagle/beagled/RemovableIndexTool.cs
==============================================================================
--- (empty file)
+++ trunk/beagle/beagled/RemovableIndexTool.cs	Sat May 31 23:25:07 2008
@@ -0,0 +1,148 @@
+//
+// RemovableIndexTool.cs
+// Single tool to create, load and unload removable indexes
+//
+// Copyright (C) 2008 D Bera <dbera web gmail com>
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Beagle;
+using Beagle.Util;
+
+// Assembly information
+[assembly: AssemblyTitle ("beagle-removable-index")]
+[assembly: AssemblyDescription ("Command-line interface for managing Beagle indexes for removable media")]
+
+public class RemovableIndexTool {
+	private static void PrintUsage ()
+	{
+		VersionFu.PrintHeader ();
+
+		string usage =
+			"Usage: beagle-removable-index [OPTIONS]\n\n" +
+			"Options:\n" +
+			"  --mount PATH\tTell beagled to load a removable index from the given directory.\n" +
+			"  --umount PATH\tTell beagled to unload a removable index from the given directory.\n" +
+			"               \tGive full path to the directory in two options above.\n" +
+			"  --help\t\tPrint this usage message.\n" +
+			"  --version\t\tPrint version information.\n";
+
+		Console.WriteLine (usage);
+	}
+
+	[DllImport("libgobject-2.0.so.0")]
+	static extern void g_type_init ();
+
+	public static void Main (string[] args) 
+	{
+		// Initialize GObject type system
+		g_type_init ();
+
+		int i = 0;
+		while (i < args.Length) {
+			
+			string arg = args [i];
+			++i;
+			string next_arg = i < args.Length ? args [i] : null;
+
+			switch (arg) {
+			case "-h":
+			case "--help":
+				PrintUsage ();
+				Environment.Exit (0);
+				break;
+
+			case "--mount":
+				if (next_arg != null)
+					MountRemovableIndex (next_arg);
+				else
+					PrintUsage ();
+				++ i;
+				break;
+
+			case "--unmount":
+				if (next_arg != null)
+					UnmountRemovableIndex (next_arg);
+				else
+					PrintUsage ();
+				++ i;
+				break;
+
+			case "--version":
+				VersionFu.PrintVersion ();
+				Environment.Exit (0);
+				break;
+
+			default:
+				PrintUsage ();
+				Environment.Exit (1);
+				break;
+
+			}
+		}
+	}
+
+	private static void MountRemovableIndex (string path)
+	{
+		Console.WriteLine ("Loading removable index from '{0}'", path);
+
+		RemovableIndexRequest req = new RemovableIndexRequest ();
+		req.Mount = true;
+		req.Path = Path.IsPathRooted (path) ? path : Path.GetFullPath (path);
+
+		ResponseMessage resp;
+		
+		try {
+			resp = req.Send ();
+		} catch (ResponseMessageException ex) {
+			Log.Error (ex, "Error in loading index.");
+			return;
+		}
+
+		RemovableIndexResponse res = (RemovableIndexResponse) resp;
+		Console.WriteLine ("Successfully added source '{0}' from {1}", res.Source, path);
+	}
+
+	private static void UnmountRemovableIndex (string path)
+	{
+		Console.WriteLine ("Unloading removable index from '{0}'", path);
+
+		RemovableIndexRequest req = new RemovableIndexRequest ();
+		req.Mount = false;
+		req.Path = Path.IsPathRooted (path) ? path : Path.GetFullPath (path);
+
+		ResponseMessage resp;
+		try {
+			resp = req.Send ();
+		} catch (ResponseMessageException ex) {
+			Log.Error (ex, "Error in unloading index.");
+			return;
+		}
+
+		RemovableIndexResponse res = (RemovableIndexResponse) resp;
+		Console.WriteLine ("Successfully unloaded source '{0}' from {1}", res.Source, path);
+	}
+}

Modified: trunk/beagle/beagled/StaticQueryable.cs
==============================================================================
--- trunk/beagle/beagled/StaticQueryable.cs	(original)
+++ trunk/beagle/beagled/StaticQueryable.cs	Sat May 31 23:25:07 2008
@@ -53,6 +53,18 @@
 			}
 		}
 
+		// FIXME: Move these to LuceneCommon if and when we decide to
+		// support adding/removing arbitrary backends at runtime
+		internal void Close ()
+		{
+			Log.Debug ("Removing static queryable {0}", IndexName);
+			if (text_cache != null)
+				text_cache.Dispose ();
+			Driver.PrimaryStore.Close ();
+			Driver.SecondaryStore.Close ();
+			FileAttributesStore.Dispose ();
+		}
+
 #if ENABLE_RDF_ADAPTER
 		protected override TextCache TextCache {
 			get { return text_cache; }

Modified: trunk/beagle/beagled/TextCache.cs
==============================================================================
--- trunk/beagle/beagled/TextCache.cs	(original)
+++ trunk/beagle/beagled/TextCache.cs	Sat May 31 23:25:07 2008
@@ -48,7 +48,7 @@
 	//
 	// See http://bugzilla.gnome.org/show_bug.cgi?329022
 
-	public class TextCache {
+	public class TextCache : IDisposable {
 
 		private const string SELF_CACHE_TAG = "*self*";
 		private const string BLOB_TAG = "*blob*";
@@ -206,6 +206,7 @@
 			LookupLinksCommand.CommandText = "SELECT links FROM links_data WHERE uri= uri";
 #endif
 		}
+
 		private SqliteConnection Open (string db_filename)
 		{
 			SqliteConnection connection = new SqliteConnection ();
@@ -214,6 +215,20 @@
 			return connection;
 		}
 
+		public void Dispose ()
+		{
+			InsertCommand.Dispose ();
+			LookupPathCommand.Dispose ();
+			LookupDataCommand.Dispose ();
+			DeleteCommand.Dispose ();
+#if ENABLE_RDF_ADAPTER
+			UpdateLinksCommand.Dispose ();
+			LookupLinksCommand.Dispose ();
+#endif
+			connection.Dispose ();
+			connection = null;
+		}
+
 		private static string UriToString (Uri uri)
 		{
 			return UriFu.UriToEscapedString (uri).Replace ("'", "''");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]