beagle r4776 - in trunk/beagle: BeagleClient beagled



Author: dbera
Date: Sat Jun  7 05:33:08 2008
New Revision: 4776
URL: http://svn.gnome.org/viewvc/beagle?rev=4776&view=rev

Log:
Implement indexing of removable sources.
* RemovableIndexControl.cs: Change API to pass locations of both the index directory and the mount point.
* FileAttributesStore.cs: Add methods to perform IsUpToDate...() against a supplied datetime instead of the last_mtime stored for the file.
* QueryDriver.cs: Move static index loading to StaticQueryable.cs and update for the API changes.
* StaticQueryable.cs: This can now create both normal static indexes and removable static indexes (which is similar to the usual index except takes an additional mount dir). Modify GetSnippet to deal with self-cached yet removable:// uris in the textcache. Add a HitFilter hook to change hit.Uri from removable:///a/b to file:///path/to/mount/dir/a/b
* RemovableIndexTool.cs: Minor changes.
* BuildIndex.cs: Add a "--removable" option which will create a removable index. The only difference is all Uris will be relative to the mount dir (which is the first <path> directory). Use Hal and other heuristics to obtain a "volume label" for the removable source and use it as Uri.Host (this value is not used currently but could be useful later). Tweak some methods since now it is dealing with two Uris, one fake removable:/// and one real file:///...


Modified:
   trunk/beagle/BeagleClient/RemovableIndexControl.cs
   trunk/beagle/beagled/BuildIndex.cs
   trunk/beagle/beagled/FileAttributesStore.cs
   trunk/beagle/beagled/QueryDriver.cs
   trunk/beagle/beagled/RemoteControlExecutors.cs
   trunk/beagle/beagled/RemovableIndexTool.cs
   trunk/beagle/beagled/StaticQueryable.cs

Modified: trunk/beagle/BeagleClient/RemovableIndexControl.cs
==============================================================================
--- trunk/beagle/BeagleClient/RemovableIndexControl.cs	(original)
+++ trunk/beagle/BeagleClient/RemovableIndexControl.cs	Sat Jun  7 05:33:08 2008
@@ -37,12 +37,12 @@
 		// 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
+		// 1. path to the config file and the index
+		public string IndexDir;
+
+		// 2. path where the removable index is mounted
 		// Separate #3 is needed in case users want to search unmounted media
-		public string Path;
+		public string MountDir;
 	}
 
 	public class RemovableIndexResponse : ResponseMessage {

Modified: trunk/beagle/beagled/BuildIndex.cs
==============================================================================
--- trunk/beagle/beagled/BuildIndex.cs	(original)
+++ trunk/beagle/beagled/BuildIndex.cs	Sat Jun  7 05:33:08 2008
@@ -64,6 +64,13 @@
 
 		/////////////////////////////////////////////////////////
 
+		// Removable index related options
+		static bool arg_removable = false;
+		static string mnt_dir = null;
+		static string volume_label = null;
+
+		/////////////////////////////////////////////////////////
+
 		// 1. Different handling of --disable-directories
 		const int MINOR_VERSION = 1;
 
@@ -218,6 +225,10 @@
 					++i;
 					break;
 
+				case "--removable":
+					arg_removable = true;
+					break;
+
 				default:
 					if (arg.StartsWith ("-") || arg.StartsWith ("--"))
 						PrintUsage ();
@@ -299,12 +310,67 @@
 					Environment.Exit (1);
 				}
 
+				bool prev_removable = static_index_config.GetOption ("Removable", false);
+				if (arg_removable != prev_removable) {
+					Log.Error ("Index previously created for {0}-removable path",
+						   (prev_removable ? "" : "non"));
+					Environment.Exit (1);
+				} else {
+					volume_label = static_index_config.GetOption ("VolumeLabel", null);
+				}
+
 				// If arg_source is not given, and prev_source is present, use prev_source
 				// as the arg_source. This is useful for re-running build-index without
 				// giving --arg_source for already existing static index
 				arg_source = prev_source;
 			}
 
+			// Removable media related options
+			if (arg_removable) {
+				if (pending_files.Count > 0) {
+					Log.Error ("Indexing individual files is not allowed for removable media.");
+					Environment.Exit (1);
+				} else if (pending_directories.Count > 1) {
+					Log.Error ("Indexing multiple root directories is not allowed for removable media.");
+					Environment.Exit (1);
+				}
+
+				mnt_dir = ((DirectoryInfo) pending_directories.Peek ()).FullName;
+				if (mnt_dir.Length != 1)
+					mnt_dir = mnt_dir.TrimEnd ('/');
+
+				// compute volume label
+				// (1) directory name if block.is_volume is false
+				// (2) hal volume.label if set
+				// (3) hal volume.uuid if set
+				Hal.Manager manager = new Hal.Manager (new Hal.Context ());
+				Hal.Device mnt_device = null;
+
+				foreach (Hal.Device device in manager.FindDeviceStringMatch ("volume.mount_point", mnt_dir))
+					mnt_device = device;
+
+				string new_volume_label = null;
+				if (mnt_device != null) {
+					new_volume_label = mnt_device.GetPropertyString ("volume.label");
+
+
+					if (String.IsNullOrEmpty (new_volume_label))
+						new_volume_label = mnt_device.GetPropertyString ("volume.uuid");
+				}
+
+				if (new_volume_label == null)
+					new_volume_label = ((DirectoryInfo) pending_directories.Peek ()).Name;
+
+				// Sanity check
+				// Volume label is part of the URI, so cannot be changed once set
+				if (volume_label == null) {
+					volume_label = new_volume_label;
+				} else if (volume_label != new_volume_label) {
+					Log.Error ("Volume label (earlier '{0}') changed (to '{1}')! You need to create a new index.", volume_label, new_volume_label);
+					Environment.Exit (1);
+				}
+			}
+
 			if (arg_source == null) {
 				DirectoryInfo dir = new DirectoryInfo (StringFu.SanitizePath (arg_output));
 				arg_source = dir.Name;
@@ -395,6 +461,15 @@
 				// The name of the source
 				static_index_config.SetOption ("Source", arg_source);
 				static_index_config ["Source"].Description = "Source of the static index";
+
+				if (arg_removable) {
+					static_index_config.SetOption ("VolumeLabel", volume_label);
+					static_index_config ["VolumeLabel"].Description = "Volume label of the removable source";
+
+					static_index_config.SetOption ("Removable", true);
+					static_index_config ["Removable"].Description = "Removable source";
+				}
+
 				Conf.SaveTo (static_index_config, config_file_path);
 			}
 
@@ -489,7 +564,7 @@
 						modified_directories.Enqueue (new DirectoryInfo (info.FullName));
 					
 					// remove
-					Uri uri = UriFu.PathToFileUri (info.FullName);
+					Uri uri = PathToUri (info.FullName);
 					indexable = new Indexable (IndexableType.Remove, uri);
 					AddToRequest (indexable);
 				}
@@ -643,12 +718,16 @@
 
 		static Indexable FileToIndexable (FileInfo file)
 		{
-			if (!file.Exists || fa_store.IsUpToDateAndFiltered (file.FullName))
+			if (!file.Exists)
+				return null;
+			
+			if (fa_store.IsUpToDateAndFiltered (PathInIndex (file.FullName),
+							    FileSystem.GetLastWriteTimeUtc (file.FullName)))
 				return null;
 
 			// Create the indexable and add the standard properties we
 			// use in the FileSystemQueryable.
-			Uri uri = UriFu.PathToFileUri (file.FullName);
+			Uri uri = PathToUri (file.FullName);
 			Indexable indexable = new Indexable (uri);
 			indexable.Timestamp = file.LastWriteTimeUtc;
 			indexable.FlushBufferCache = true;
@@ -657,7 +736,12 @@
 
 			// Store directory name in the index
 			string dirname = file.DirectoryName;
-			indexable.AddProperty (Property.NewUnsearched (Property.ParentDirUriPropKey, UriFu.PathToFileUri (dirname)));
+			indexable.AddProperty (Property.NewUnsearched (Property.ParentDirUriPropKey, PathToUri (dirname)));
+
+			if (arg_removable) {
+				indexable.AddProperty (Property.NewKeyword ("beagle:RemovableVolume", volume_label));
+				indexable.ContentUri = UriFu.PathToFileUri (file.FullName);
+			}
 
 			return indexable;
 		}
@@ -669,13 +753,13 @@
 
 			// Check if the directory information is stored in attributes store
 			// And if the mtime of the directory is same as that in the attributes store
-			FileAttributes attr = fa_store.Read (dir.FullName);
+			FileAttributes attr = fa_store.Read (PathInIndex (dir.FullName));
 
 			// If the directory exists in the fa store, then it is already indexed.
 			if (attr != null) {
 				// If we don't care about deleted content then we are fine.
 				// If the attributes are up-to-date, then we are fine too.
-				if (! arg_delete || FileAttributesStore.IsUpToDate (dir.FullName, attr))
+				if (! arg_delete || FileAttributesStore.IsUpToDate (attr, FileSystem.GetLastWriteTimeUtc (dir.FullName)))
 					return null;
 
 				// But the last write time needs to be uptodate to support enable-deletion,
@@ -686,7 +770,7 @@
 
 			// Create the indexable and add the standard properties we
 			// use in the FileSystemQueryable.
-			Uri uri = UriFu.PathToFileUri (dir.FullName);
+			Uri uri = PathToUri (dir.FullName);
 			Indexable indexable = new Indexable (uri);
 			indexable.MimeType = "inode/directory";
 			indexable.NoContent = true;
@@ -700,13 +784,42 @@
 
 			// Add directory name property
 			string dirname = dir.Parent.FullName;
-			indexable.AddProperty (Property.NewUnsearched (Property.ParentDirUriPropKey, UriFu.PathToFileUri (dirname)));
+			indexable.AddProperty (Property.NewUnsearched (Property.ParentDirUriPropKey, PathToUri (dirname)));
 
 			indexable.AddProperty (Property.NewBool (Property.IsDirectoryPropKey, true));
 
+			if (arg_removable)
+				indexable.AddProperty (Property.NewKeyword ("beagle:removable", volume_label));
+
 			return indexable;
 		}
-		
+
+		static string PathInIndex (string fullpath)
+		{
+			if (! arg_removable)
+				return fullpath;
+
+			if (fullpath == mnt_dir)
+				return "/";
+
+			if (fullpath.IndexOf (mnt_dir) != 0) {
+				Log.Warn ("Outside mounted directory: {0}", fullpath);
+				return fullpath;
+			}
+
+			return fullpath.Remove (0, mnt_dir.Length);
+		}
+
+		static Uri PathToUri (string fullpath)
+		{
+			fullpath = PathInIndex (fullpath);
+
+			return new Uri (String.Format ("removable{0}{1}{2}",
+							Uri.SchemeDelimiter,
+							volume_label,
+							StringFu.HexEscape (fullpath)), true);
+		}
+
 		class Dirent {
 			private bool is_directory;
 			private string path;
@@ -749,7 +862,7 @@
 		static ICollection GetAllItemsInDirectory (DirectoryInfo dir)
 		{
 			// form the query
-			string parent_uri_str = UriFu.PathToFileUri (dir.FullName).ToString ();
+			string parent_uri_str = PathToUri (dir.FullName).ToString ();
 
 			// Instead of taking the painfull way of using BeagleAnalyzer, lets just add the prefix manually
 			// LuceneCommon thinks exposing secret property type encoding is bad, I think so too... except for now
@@ -904,6 +1017,13 @@
 				"  --disable-restart\t\tDon't restart when memory usage gets above a certain threshold.\n" +
 				"  --disable-on-battery\t\tDisable indexer while on battery power.\n";
 
+			usage +="\n" +
+				"Removable media options:\n" +
+				"  --removable\t\t\tCreate a removable media.\n" +
+				"\n" +
+				" * Use --source [name] to specify a name for the removable media.\n" +
+				" * You can specify only one <path>. Paths will be stored relative to <path>.\n";
+
 			Console.WriteLine (usage);
 			Environment.Exit (0);
 		}

Modified: trunk/beagle/beagled/FileAttributesStore.cs
==============================================================================
--- trunk/beagle/beagled/FileAttributesStore.cs	(original)
+++ trunk/beagle/beagled/FileAttributesStore.cs	Sat Jun  7 05:33:08 2008
@@ -157,8 +157,25 @@
 			return (attr.LastWriteTime >= FileSystem.GetLastWriteTimeUtc (path));
 		}
 
+		// To be used if the last_write_time to use for comparison is not the
+		// one obtained from path
+		public static bool IsUpToDate (FileAttributes attr, DateTime last_write_time)
+		{
+			if (attr == null)
+				return false;
+
+			return (attr.LastWriteTime >= last_write_time);
+		}
+
 		public bool IsUpToDate (string path, Filter filter)
 		{
+			return IsUpToDate (path, filter, DateTime.MaxValue);
+		}
+
+		// To be used if the last_write_time to use for comparison is not the
+		// one obtained from path
+		public bool IsUpToDate (string path, Filter filter, DateTime last_write_time)
+		{
 			FileAttributes attr;
 
 			attr = Read (path);
@@ -189,11 +206,21 @@
 					return false;
 			} 
 
-			return IsUpToDate (path, attr);
+			if (last_write_time == DateTime.MaxValue)
+				return (attr.LastWriteTime >= FileSystem.GetLastWriteTimeUtc (path));
+			else
+				return (attr.LastWriteTime >= last_write_time);
 		}
 
 		public bool IsUpToDateAndFiltered (string path)
 		{
+			return IsUpToDateAndFiltered (path, DateTime.MaxValue);
+		}
+
+		// To be used if the last_write_time to use for comparison is not the
+		// one obtained from path
+		public bool IsUpToDateAndFiltered (string path, DateTime last_write_time)
+		{
 			FileAttributes attr;
 
 			attr = Read (path);
@@ -203,10 +230,14 @@
 			if (attr == null)
 				return false;
 
-			if (! FilterFactory.DirtyFilterCache)
+			if (! FilterFactory.DirtyFilterCache) {
 				// If the filters are same as in last run,
 				// since attr is not null, check the timestamps (bypass HasFilterInfo)
-				return IsUpToDate (path, attr);
+				if (last_write_time == DateTime.MaxValue)
+					return (attr.LastWriteTime >= FileSystem.GetLastWriteTimeUtc (path));
+				else
+					return (attr.LastWriteTime >= last_write_time);
+			}
 
 			// If there is a new filter in the mean time
 			// take previous filter information into consideration.
@@ -218,11 +249,21 @@
 			if (current_filter_version > attr.FilterVersion)
 				return false;
 
-			return IsUpToDate (path, attr);
+			if (last_write_time == DateTime.MaxValue)
+				return (attr.LastWriteTime >= FileSystem.GetLastWriteTimeUtc (path));
+			else
+				return (attr.LastWriteTime >= last_write_time);
 		}
 
 		public bool IsUpToDate (string path)
 		{
+			return IsUpToDate (path, DateTime.MaxValue);
+		}
+
+		// To be used if the last_write_time to use for comparison is not the
+		// one obtained from path
+		public bool IsUpToDate (string path, DateTime last_write_time)
+		{
 			return IsUpToDate (path, (Filter) null);
 		}
 

Modified: trunk/beagle/beagled/QueryDriver.cs
==============================================================================
--- trunk/beagle/beagled/QueryDriver.cs	(original)
+++ trunk/beagle/beagled/QueryDriver.cs	Sat Jun  7 05:33:08 2008
@@ -200,12 +200,16 @@
 
 			int count = 0;
 
+			Queryable queryable;
 			foreach (DirectoryInfo index_dir in new DirectoryInfo (PathFinder.SystemIndexesDir).GetDirectories ()) {
 				if (! UseQueryable (index_dir.Name))
 					continue;
 				
-				if (LoadStaticQueryable (index_dir, QueryDomain.System) != null)
+				queryable = StaticQueryable.LoadStaticQueryable (index_dir, QueryDomain.System);
+				if (queryable != null) {
+					iqueryable_to_queryable [queryable.IQueryable] = queryable;
 					count++;
+				}
 			}
 
 			Logger.Log.Info ("Found {0} system-wide indexes.", count);
@@ -226,6 +230,7 @@
 				}
 			}
 
+			Queryable queryable;
 			foreach (string path in static_queryables) {
 				DirectoryInfo index_dir = new DirectoryInfo (StringFu.SanitizePath (path));
 
@@ -233,8 +238,11 @@
 					continue;
 				
 				// FIXME: QueryDomain might be other than local
-				if (LoadStaticQueryable (index_dir, QueryDomain.Local) != null)
+				queryable = StaticQueryable.LoadStaticQueryable (index_dir, QueryDomain.Local);
+				if (queryable != null) {
+					iqueryable_to_queryable [queryable.IQueryable] = queryable;
 					count++;
+				}
 			}
 
 			Logger.Log.Info ("Found {0} user-configured static indexes..", count);
@@ -242,57 +250,6 @@
 			static_queryables = null;
 		}
 
-		// Instantiates and loads a StaticQueryable from an index directory
-		static private Queryable LoadStaticQueryable (DirectoryInfo index_dir, QueryDomain query_domain) 
-		{
-			StaticQueryable static_queryable = null;
-			
-			if (!index_dir.Exists)
-				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 null;
-			} catch (Exception e) {
-				Logger.Log.Error (e, "Caught exception while instantiating static queryable: {0}", index_dir.Name);
-				return null;
-			}
-
-			if (static_queryable == null)
-				return null;
-
-			// Load StaticIndex.xml from index_dir.FullName/config
-			string config_file_path = Path.Combine (index_dir.FullName, "StaticIndex.xml");
-			Config static_index_config;
-			try {
-				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 null;
-				}
-			} catch (Exception e) {
-				Log.Error (e, "Caught exception while reading config from {0}", config_file_path);
-				return null;
-			}
-
-			string source = static_index_config.GetOption ("Source", null);
-			if (source == null) {
-				Log.Error ("Invalid config file: {0}", config_file_path);
-				return null;
-			}
-
-			QueryableFlavor flavor = new QueryableFlavor ();
-			flavor.Name = source;
-			flavor.Domain = query_domain;
-
-			Queryable queryable = new Queryable (flavor, static_queryable);
-			iqueryable_to_queryable [static_queryable] = queryable;
-
-			return queryable;
-		}
-
 		////////////////////////////////////////////////////////
 
 		private static ArrayList assemblies = null;
@@ -745,17 +702,17 @@
 
 		private static Dictionary<string, Queryable> removable_queryables = new Dictionary<string, Queryable> (4); // small number
 
-		internal static ResponseMessage HandleRemovableIndexRequest (string path, bool to_mount)
+		internal static ResponseMessage HandleRemovableIndexRequest (bool to_mount, string index_dir, string mnt_dir)
 		{
 			lock (removable_queryables) {
 				if (to_mount)
-					return AddRemovableIndex (path);
+					return AddRemovableIndex (index_dir, mnt_dir);
 				else
-					return RemoveRemovableIndex (path);
+					return RemoveRemovableIndex (index_dir, mnt_dir);
 			}
 		}
 
-		private static ResponseMessage AddRemovableIndex (string path)
+		private static ResponseMessage AddRemovableIndex (string path, string mnt_dir)
 		{
 			DirectoryInfo index_dir = new DirectoryInfo (StringFu.SanitizePath (path));
 			if (! index_dir.Exists) {
@@ -766,6 +723,16 @@
 				return msg;
 			}
 
+			// Allow late loading of mount dir ?
+			mnt_dir = StringFu.SanitizePath (mnt_dir);
+			if (! Directory.Exists (mnt_dir)) {
+				ErrorResponse msg;
+				msg = new ErrorResponse ();
+				msg.ErrorMessage = "Adding removable index failed";
+				msg.Details = String.Format ("Mount directory '{0}' does not exist.", mnt_dir);
+				return msg;
+			}
+
 			if (removable_queryables.ContainsKey (path)) {
 				ErrorResponse msg;
 				msg = new ErrorResponse ();
@@ -778,7 +745,7 @@
 
 			try {
 				iqueryable_lock.AcquireWriterLock (System.Threading.Timeout.Infinite);
-				removable_queryable = LoadStaticQueryable (index_dir, QueryDomain.Local);
+				removable_queryable = StaticQueryable.LoadRemovableQueryable (index_dir, mnt_dir);
 			} finally {
 				iqueryable_lock.ReleaseWriterLock ();
 			}
@@ -786,6 +753,7 @@
 			if (removable_queryable == null)
 				return new ErrorResponse ("Adding removable index failed");
 
+			iqueryable_to_queryable [removable_queryable.IQueryable] = removable_queryable;
 			removable_queryables [path] = removable_queryable;
 
 			RemovableIndexResponse resp = new RemovableIndexResponse ();
@@ -794,7 +762,7 @@
 			return resp;
 		}
 
-		private static ResponseMessage RemoveRemovableIndex (string path)
+		private static ResponseMessage RemoveRemovableIndex (string path, string mnt_dir)
 		{
 			if (! removable_queryables.ContainsKey (path)) {
 				ErrorResponse msg;
@@ -814,6 +782,14 @@
 			}
 
 			StaticQueryable static_queryable = (StaticQueryable) removable_queryable.IQueryable;
+			if (static_queryable.RemovableMountDir != mnt_dir) {
+				ErrorResponse msg;
+				msg = new ErrorResponse ();
+				msg.ErrorMessage = "Removing removable-index failed";
+				msg.Details = String.Format ("No index mounted at {0}.", mnt_dir);
+				return msg;
+			}
+
 			static_queryable.Close ();
 
 			removable_queryables.Remove (path);

Modified: trunk/beagle/beagled/RemoteControlExecutors.cs
==============================================================================
--- trunk/beagle/beagled/RemoteControlExecutors.cs	(original)
+++ trunk/beagle/beagled/RemoteControlExecutors.cs	Sat Jun  7 05:33:08 2008
@@ -105,10 +105,11 @@
 		public override ResponseMessage Execute (RequestMessage req)
 		{
 			RemovableIndexRequest r = (RemovableIndexRequest) req;
-			string path = r.Path;
 			bool to_mount = r.Mount;
+			string index_dir = r.IndexDir;
+			string mnt_dir = r.MountDir;
 
-			return QueryDriver.HandleRemovableIndexRequest (path, to_mount);
+			return QueryDriver.HandleRemovableIndexRequest (to_mount, index_dir, mnt_dir);
 		}
 	}
 }

Modified: trunk/beagle/beagled/RemovableIndexTool.cs
==============================================================================
--- trunk/beagle/beagled/RemovableIndexTool.cs	(original)
+++ trunk/beagle/beagled/RemovableIndexTool.cs	Sat Jun  7 05:33:08 2008
@@ -1,6 +1,6 @@
 //
 // RemovableIndexTool.cs
-// Single tool to create, load and unload removable indexes
+// Tool to load and unload removable indexes
 //
 // Copyright (C) 2008 D Bera <dbera web gmail com>
 //
@@ -42,11 +42,13 @@
 		VersionFu.PrintHeader ();
 
 		string usage =
-			"Usage: beagle-removable-index [OPTIONS]\n\n" +
+			"Usage: beagle-removable-index --indexdir INDEXDIR --mount DIR\n" +
+			"       beagle-removable-index --indexdir INDEXDIR --unmount DIR\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" +
+			"  --indexdir DIR\tSpecify the path to the index directory.\n" +
+			"  --mount DIR \tTell beagled to load a removable index from the given directory.\n" +
+			"  --umount DIR\tTell beagled to unload a removable index from the given directory.\n" +
+			"               \tGive full path to the directory in the above options.\n\n" +
 			"  --help\t\tPrint this usage message.\n" +
 			"  --version\t\tPrint version information.\n";
 
@@ -61,6 +63,10 @@
 		// Initialize GObject type system
 		g_type_init ();
 
+		string index_dir = null;
+		string target_dir = null;
+		bool mount = false;
+
 		int i = 0;
 		while (i < args.Length) {
 			
@@ -75,19 +81,25 @@
 				Environment.Exit (0);
 				break;
 
-			case "--mount":
+			case "--indexdir":
 				if (next_arg != null)
-					MountRemovableIndex (next_arg);
-				else
-					PrintUsage ();
+					index_dir = next_arg;
+				++ i;
+				break;
+
+			case "--mount":
+				if (next_arg != null) {
+					target_dir = next_arg;
+					mount = true;
+				}
 				++ i;
 				break;
 
 			case "--unmount":
-				if (next_arg != null)
-					UnmountRemovableIndex (next_arg);
-				else
-					PrintUsage ();
+				if (next_arg != null) {
+					target_dir = next_arg;
+					mount = false;
+				}
 				++ i;
 				break;
 
@@ -103,15 +115,26 @@
 
 			}
 		}
+
+		if (target_dir == null || index_dir == null) {
+			PrintUsage ();
+			Environment.Exit (1);
+		}
+
+		if (mount)
+			MountRemovableIndex (index_dir, target_dir);
+		else
+			UnmountRemovableIndex (index_dir, target_dir);
 	}
 
-	private static void MountRemovableIndex (string path)
+	private static void MountRemovableIndex (string index_dir, string mnt_dir)
 	{
-		Console.WriteLine ("Loading removable index from '{0}'", path);
+		Console.WriteLine ("Loading removable index from '{0}' for '{1}'", index_dir, mnt_dir);
 
 		RemovableIndexRequest req = new RemovableIndexRequest ();
 		req.Mount = true;
-		req.Path = Path.IsPathRooted (path) ? path : Path.GetFullPath (path);
+		req.IndexDir = Path.IsPathRooted (index_dir) ? index_dir : Path.GetFullPath (index_dir);
+		req.MountDir = Path.IsPathRooted (mnt_dir) ? mnt_dir : Path.GetFullPath (mnt_dir);
 
 		ResponseMessage resp;
 		
@@ -123,16 +146,17 @@
 		}
 
 		RemovableIndexResponse res = (RemovableIndexResponse) resp;
-		Console.WriteLine ("Successfully added source '{0}' from {1}", res.Source, path);
+		Console.WriteLine ("Successfully mounted '{0}'@{1} from {2}", res.Source, mnt_dir, index_dir);
 	}
 
-	private static void UnmountRemovableIndex (string path)
+	private static void UnmountRemovableIndex (string index_dir, string mnt_dir)
 	{
-		Console.WriteLine ("Unloading removable index from '{0}'", path);
+		Console.WriteLine ("Unloading removable index from '{0}' for '{1}'", index_dir, mnt_dir);
 
 		RemovableIndexRequest req = new RemovableIndexRequest ();
 		req.Mount = false;
-		req.Path = Path.IsPathRooted (path) ? path : Path.GetFullPath (path);
+		req.IndexDir = Path.IsPathRooted (index_dir) ? index_dir : Path.GetFullPath (index_dir);
+		req.MountDir = Path.IsPathRooted (mnt_dir) ? mnt_dir : Path.GetFullPath (mnt_dir);
 
 		ResponseMessage resp;
 		try {
@@ -143,6 +167,6 @@
 		}
 
 		RemovableIndexResponse res = (RemovableIndexResponse) resp;
-		Console.WriteLine ("Successfully unloaded source '{0}' from {1}", res.Source, path);
+		Console.WriteLine ("Successfully unloaded '{0}'@{1} from {2}", res.Source, mnt_dir, index_dir);
 	}
 }

Modified: trunk/beagle/beagled/StaticQueryable.cs
==============================================================================
--- trunk/beagle/beagled/StaticQueryable.cs	(original)
+++ trunk/beagle/beagled/StaticQueryable.cs	Sat Jun  7 05:33:08 2008
@@ -40,6 +40,14 @@
 
 		protected TextCache text_cache = null;
 
+		// If not null, then this is a removable index and
+		// mount_dir is where the removable media is mounted
+		private string mount_dir = null;
+
+		public string RemovableMountDir {
+			get { return mount_dir; }
+		}
+
 		public StaticQueryable (string index_name, string index_path, bool read_only_mode) : base (index_path, read_only_mode)
 		{
 			Logger.Log.Debug ("Initializing static queryable: {0}", index_path);
@@ -53,6 +61,69 @@
 			}
 		}
 
+		// Instantiates and loads a StaticQueryable from an index directory
+		internal static Queryable LoadStaticQueryable (DirectoryInfo index_dir, QueryDomain query_domain)
+		{
+			StaticQueryable static_queryable = null;
+			
+			if (!index_dir.Exists)
+				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 null;
+			} catch (Exception e) {
+				Logger.Log.Error (e, "Caught exception while instantiating static queryable: {0}", index_dir.Name);
+				return null;
+			}
+
+			if (static_queryable == null)
+				return null;
+
+			// Load StaticIndex.xml from index_dir.FullName/config
+			string config_file_path = Path.Combine (index_dir.FullName, "StaticIndex.xml");
+			Config static_index_config;
+			try {
+				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 null;
+				}
+			} catch (Exception e) {
+				Log.Error (e, "Caught exception while reading config from {0}", config_file_path);
+				return null;
+			}
+
+			string source = static_index_config.GetOption ("Source", null);
+			if (source == null) {
+				Log.Error ("Invalid config file: {0}", config_file_path);
+				return null;
+			}
+
+			QueryableFlavor flavor = new QueryableFlavor ();
+			flavor.Name = source;
+			flavor.Domain = query_domain;
+
+			Queryable queryable = new Queryable (flavor, static_queryable);
+			return queryable;
+		}
+
+		internal static Queryable LoadRemovableQueryable (DirectoryInfo index_dir, string mnt_dir)
+		{
+			Queryable queryable = LoadStaticQueryable (index_dir, QueryDomain.Local);
+			if (queryable == null)
+				return null;
+
+			StaticQueryable static_queryable;
+			static_queryable = (StaticQueryable) queryable.IQueryable;
+
+			static_queryable.mount_dir = mnt_dir;
+
+			return queryable;
+		}
+
 		// FIXME: Move these to LuceneCommon if and when we decide to
 		// support adding/removing arbitrary backends at runtime
 		internal void Close ()
@@ -81,9 +152,21 @@
 			if (text_cache == null)
 				return null;
 
+			Uri uri;
+
+			if (mount_dir == null || hit ["beagle:RemovableUri"] == null)
+				uri = hit.Uri;
+			else
+				uri = UriFu.EscapedStringToUri (hit ["beagle:RemovableUri"]);
+
 			// Look up the hit in our local text cache.
-			TextReader reader = text_cache.GetReader (hit.Uri);
-			if (reader == null)
+			// Need to handle self-cached removable:/// uris
+			bool self_cache = true;
+			TextReader reader = text_cache.GetReader (uri, ref self_cache);
+
+			if (self_cache)
+				reader = new StreamReader (hit.Uri.LocalPath);
+			else if (reader == null)
 				return null;
 			
 			return SnippetFu.GetSnippet (query_terms, reader, full_text, ctx_length, snp_length);
@@ -105,5 +188,25 @@
 				return false;
 			}
 		}
+
+		// Remap uri based on mount point for removable indexes
+		// FIXME: Allow option to search unmounted media ? Return false in that case.
+		override protected bool HitFilter (Hit hit)
+		{
+			if (mount_dir == null || hit.Uri.Scheme != "removable")
+				return true;
+
+			hit.AddProperty (Beagle.Property.NewKeyword ("beagle:RemovableUri",
+								     hit.EscapedUri));
+
+			string path = hit.Uri.LocalPath;
+			path = path.Substring (1); // Remove initial '/'
+			path = Path.Combine (mount_dir, path);
+			hit.Uri = UriFu.PathToFileUri (path);
+
+			hit.AddProperty (Beagle.Property.NewKeyword ("fixme:mount_dir", mount_dir));
+
+			return true;
+		}
 	}
 }



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