Oops, fix a broken part of the patch
[beagle.git] / beagled / RemoteIndexer.cs
blob214a4e7324eb927640ba062a8e0c66f10ea045ef
1 //
2 // RemoteIndexer.cs
3 //
4 // Copyright (C) 2005 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 using System;
28 using System.Diagnostics;
29 using System.IO;
30 using System.Threading;
31 using Mono.Unix;
33 using Beagle;
34 using Beagle.Util;
36 namespace Beagle.Daemon {
38 public class RemoteIndexer : IIndexer {
40 static string helper_path;
42 string remote_index_name;
43 int remote_index_minor_version = 0;
44 int last_item_count = -1;
46 static RemoteIndexer ()
48 string bihp = Environment.GetEnvironmentVariable ("_BEAGLED_INDEX_HELPER_PATH");
49 if (bihp == null)
50 throw new Exception ("_BEAGLED_INDEX_HELPER_PATH not set!");
52 helper_path = Path.GetFullPath (Path.Combine (bihp, "beagled-index-helper"));
53 if (! File.Exists (helper_path))
54 throw new Exception ("Could not find " + helper_path);
55 Logger.Log.Debug ("Found index helper at {0}", helper_path);
58 static public IIndexer NewRemoteIndexer (string name, int minor_version)
60 return new RemoteIndexer (name, minor_version);
63 public RemoteIndexer (string name, int minor_version)
65 this.remote_index_name = name;
66 this.remote_index_minor_version = minor_version;
69 public IndexerReceipt [] Flush (IndexerRequest request)
71 // If there isn't actually any work to do, just return
72 // an empty array.
73 if (request.IsEmpty)
74 return new IndexerReceipt [0];
76 // Iterate through the items in the IndexerRequest to
77 // store the streams before passing them to the helper.
78 foreach (Indexable indexable in request.Indexables) {
79 if (indexable.Type == IndexableType.Add)
80 indexable.StoreStream ();
83 RemoteIndexerRequest remote_request;
84 remote_request = new RemoteIndexerRequest ();
85 remote_request.RemoteIndexName = this.remote_index_name;
86 remote_request.RemoteIndexMinorVersion = this.remote_index_minor_version;
87 remote_request.Request = request;
89 RemoteIndexerResponse response;
90 response = SendRequest (remote_request);
92 if (response == null) {
93 Logger.Log.Error ("Something terrible happened --- Flush failed");
94 request.Cleanup ();
95 return null;
98 last_item_count = response.ItemCount;
100 return response.Receipts;
103 public int GetItemCount ()
105 if (last_item_count == -1) {
106 // Send an empty indexing request to cause the last item count to be
107 // initialized.
108 RemoteIndexerRequest request;
109 request = new RemoteIndexerRequest ();
111 RemoteIndexerResponse response;
112 response = SendRequest (request);
113 if (response != null)
114 last_item_count = response.ItemCount;
115 else
116 Logger.Log.Error ("Something terrible happened --- GetItemCount failed");
119 return last_item_count;
122 /////////////////////////////////////////////////////////
124 private RemoteIndexerResponse SendRequest (RemoteIndexerRequest request)
126 RemoteIndexerResponse response = null;
127 int exception_count = 0;
128 bool start_helper_by_hand = false;
130 if (Environment.GetEnvironmentVariable ("BEAGLE_RUN_HELPER_BY_HAND") != null)
131 start_helper_by_hand = true;
133 request.RemoteIndexName = remote_index_name;
134 request.RemoteIndexMinorVersion = remote_index_minor_version;
136 while (response == null
137 && exception_count < 5
138 && ! Shutdown.ShutdownRequested) {
140 bool need_helper = false;
142 //Logger.Log.Debug ("Sending request!");
143 try {
144 response = request.Send () as RemoteIndexerResponse;
145 //Logger.Log.Debug ("Done sending request");
146 } catch (ResponseMessageException ex) {
147 Logger.Log.Debug ("Caught ResponseMessageException: {0}", ex.Message);
149 if (ex.InnerException is System.Net.Sockets.SocketException) {
150 Logger.Log.Debug ("InnerException is SocketException -- we probably need to launch a helper");
151 need_helper = true;
152 } else if (ex.InnerException is IOException) {
153 Logger.Log.Debug ("InnerException is IOException -- we probably need to launch a helper");
154 need_helper = true;
155 } else {
156 Logger.Log.Debug ("Exception was unexpected. Details: {0}", ex);
160 // If we caught an exception...
161 if (response == null) {
162 if (! start_helper_by_hand || ! need_helper)
163 ++exception_count;
165 if (start_helper_by_hand) {
166 // Sleep briefly before trying again.
167 Thread.Sleep (1000);
168 } else {
169 // Try to activate the helper.
170 LaunchHelper ();
175 if (response == null && exception_count >= 5)
176 Logger.Log.Error ("Exception limit exceeded trying to activate a helper. Giving up on indexing!");
178 return response;
181 /////////////////////////////////////////////////////////
183 static bool CheckHelper ()
185 string storage_dir = PathFinder.GetRemoteStorageDir (false);
187 if (storage_dir == null)
188 return false;
190 // FIXME: We shouldn't need to know the path to the helper socket.
191 string socket_name = Path.Combine (storage_dir, "socket-helper");
193 if (! File.Exists (socket_name))
194 return false;
196 // Open, and then immediately close, a connection to the helper's socket.
197 try {
198 UnixClient test_client;
199 test_client = new UnixClient (socket_name);
200 test_client.Close ();
201 return true;
202 } catch (Exception ex) {
203 return false;
207 static object helper_lock = new object ();
209 static void LaunchHelper ()
211 // If we are in the process of shutting down, return immediately.
212 if (Shutdown.ShutdownRequested)
213 return;
215 lock (helper_lock) {
217 // If a helper appears to be running, return immediately.
218 if (CheckHelper ())
219 return;
221 Logger.Log.Debug ("Launching helper process");
223 Process p = new Process ();
224 p.StartInfo.UseShellExecute = false;
225 p.StartInfo.FileName = helper_path;
226 p.Start ();
228 Logger.Log.Debug ("IndexHelper PID is {0}", p.Id);
230 // Poll the helper's socket. Wait up to a minute
231 // (500 ms * 120 times) for the helper to be ready
232 // to handle requests.
233 Stopwatch watch = new Stopwatch ();
234 watch.Start ();
235 int poll_count = 0;
236 bool found_helper;
237 do {
238 Thread.Sleep (500);
239 ++poll_count;
240 found_helper = CheckHelper ();
241 } while (poll_count < 120
242 && ! found_helper
243 && ! Shutdown.ShutdownRequested);
244 watch.Stop ();
246 if (! found_helper)
247 throw new Exception (String.Format ("Couldn't launch helper process {0}", p.Id));
249 Logger.Log.Debug ("Found IndexHelper ({0}) in {1}", p.Id, watch);