3 using System
.Diagnostics
;
5 using System
.Threading
;
11 static public class Daemon
{
13 public delegate void StartedHandler (string daemon_version
);
14 public delegate void IdleHandler ();
15 public delegate void VerifiedHandler (bool index_is_sane
);
17 static public bool UseHeapBuddy
= false;
19 /////////////////////////////////////////////////////////////
21 static Beagle
.Query index_listener_query
= null;
23 static private void SetupIndexListener ()
25 index_listener_query
= new Beagle
.Query ();
26 index_listener_query
.IsIndexListener
= true;
28 index_listener_query
.HitsAddedEvent
+= OnHitsAdded
;
29 index_listener_query
.HitsSubtractedEvent
+= OnHitsSubtracted
;
31 index_listener_query
.SendAsync ();
34 static private void OnHitsAdded (Beagle
.HitsAddedResponse response
)
36 //Log.Spew ("Added {0} hits!", response.Hits.Count);
37 //foreach (Beagle.Hit hit in response.Hits)
38 //Log.Spew (" {0}", hit.Uri);
41 static private void OnHitsSubtracted (Beagle
.HitsSubtractedResponse response
)
43 //Log.Spew ("Subtracted {0} uris!", response.Uris.Count);
46 /////////////////////////////////////////////////////////////
48 private class WaitForStartClosure
{
51 StartedHandler started
;
52 int failure_count
= 0;
54 public WaitForStartClosure (Process process
, StartedHandler started
)
56 this.process
= process
;
57 this.started
= started
;
62 // Wait a little bit before we start pinging the daemon. This is
63 // an attempt to work around a mono crash.
66 Action
.Add (50, new GLib
.TimeoutHandler (OurTimeoutHandler
));
69 private bool OurTimeoutHandler ()
72 // Oops, process.HasExited doesn't work in mono. Grrr.
73 if (process
.HasExited
) {
74 Log
.Failure ("Beagle daemon has terminated unexpectedly - exit code {0}",
82 Beagle
.RequestMessage request
;
83 request
= new Beagle
.DaemonInformationRequest ();
85 Beagle
.ResponseMessage response
= null;
87 //Log.Spew ("Pinging daemon!");
88 response
= request
.Send ();
91 if (response
== null) {
94 if (failure_count
% 20 == 0)
95 Log
.Info ("Ping attempt {0} failed", failure_count
);
97 // If we've already tried a bunch of times, just give up.
98 if (failure_count
>= 100) {
99 Log
.Failure ("Could not contact daemon after {0} pings", failure_count
);
105 return true; // wait a bit, then try again
108 Beagle
.DaemonInformationResponse info
;
109 info
= (Beagle
.DaemonInformationResponse
) response
;
111 Log
.Spew ("Successfully pinged daemon (version={0})", info
.Version
);
113 SetupIndexListener ();
116 started (info
.Version
);
118 return false; // all done
122 static public void Start (StartedHandler started
)
124 Log
.Spew ("Starting daemon");
127 beagled
= Environment
.GetEnvironmentVariable ("BEAGLED_COMMAND");
130 args
= "--debug-memory --bg --allow-backend files";
133 args
+= " --heap-buddy";
137 p
.StartInfo
.UseShellExecute
= false;
139 p
.StartInfo
.FileName
= beagled
;
140 p
.StartInfo
.Arguments
= args
;
142 p
.StartInfo
.EnvironmentVariables
["BEAGLE_HOME"] = Beagle
.Util
.PathFinder
.HomeDir
;
143 p
.StartInfo
.EnvironmentVariables
["BEAGLE_EXERCISE_THE_DOG"] = "1";
144 p
.StartInfo
.EnvironmentVariables
["BEAGLE_UNDER_BLUDGEON"] = "1";
145 p
.StartInfo
.EnvironmentVariables
["BEAGLE_HEAP_BUDDY_DIR"] = Path
.Combine (Beagle
.Util
.PathFinder
.HomeDir
,
150 WaitForStartClosure closure
;
151 closure
= new WaitForStartClosure (p
, started
);
155 /////////////////////////////////////////////////////////////
157 private class WaitUntilIdleClosure
{
160 int failure_count
= 0;
162 bool optimized
= false;
165 public WaitUntilIdleClosure (IdleHandler idle
)
172 Action
.Add (200, new GLib
.TimeoutHandler (OurTimeoutHandler
));
175 private bool OurTimeoutHandler ()
178 sw
= new Stopwatch ();
182 Beagle
.RequestMessage request
;
183 request
= new Beagle
.DaemonInformationRequest ();
185 Beagle
.ResponseMessage response
= null;
187 response
= request
.Send ();
190 if (response
== null) {
192 // FIXME: we should abort if we have too many failures
193 if (failure_count
> 9)
194 Log
.Info ("Status request attempt {0} failed", failure_count
);
195 return true; // wait a bit, then try again
199 status_str
= ((Beagle
.DaemonInformationResponse
) response
).HumanReadableStatus
;
201 if (status_str
.IndexOf ("Waiting on empty queue") == -1) {
203 Log
.Spew ("Waiting for daemon to become idle");
205 if (busy_count
% 10 == 0)
206 Log
.Spew ("Still waiting for daemon to become idle...");
207 return true; // wait a bit, then try again
210 if (failure_count
> 0 || busy_count
> 0)
211 Log
.Spew ("Daemon is idle after {0}", sw
);
213 Log
.Spew ("Daemon is idle");
216 Log
.Spew ("Requesting index optimization");
222 request
= new Beagle
.OptimizeIndexesRequest ();
226 Log
.Failure ("Optimize request failed");
227 // FIXME: we should probably terminate here, or something
230 return true; // wait for optimize to finish
236 return false; // all done
240 static public void WaitUntilIdle (IdleHandler idle
)
242 WaitUntilIdleClosure closure
;
243 closure
= new WaitUntilIdleClosure (idle
);
247 /////////////////////////////////////////////////////////////
249 private class WaitUntilVerifiedClosure
{
251 FileSystemObject root
;
252 VerifiedHandler verified
;
254 public WaitUntilVerifiedClosure (FileSystemObject root
,
255 VerifiedHandler verified
)
258 this.verified
= verified
;
263 WaitUntilIdle (OurIdleHandler
);
266 private void OurIdleHandler ()
269 is_correct
= SanityCheck
.VerifyIndex (root
);
270 if (verified
!= null)
271 verified (is_correct
);
275 static public void WaitUntilVerified (FileSystemObject root
, VerifiedHandler verified
)
277 WaitUntilVerifiedClosure closure
;
278 closure
= new WaitUntilVerifiedClosure (root
, verified
);
282 /////////////////////////////////////////////////////////////
284 static public void Shutdown ()
286 Beagle
.RequestMessage request
;
287 request
= new Beagle
.ShutdownRequest ();
289 Log
.Spew ("Shutting down daemon");
294 Log
.Failure ("beagled shutdown failed");