Oops, fix a broken part of the patch
[beagle.git] / beagled / IndexHelper / IndexHelper.cs
blob91683cff705db3c5d8c16ad01ceb426448bfe86c
2 // IndexHelper.cs
3 //
4 // Copyright (C) 2005 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in all
16 // 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 FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 // SOFTWARE.
28 using System;
29 using System.Collections;
30 using System.IO;
31 using SNS = System.Net.Sockets;
32 using System.Threading;
34 using Gtk;
36 using Beagle.Daemon;
37 using Beagle.Util;
39 namespace Beagle.IndexHelper {
41 class IndexHelperTool {
43 static DateTime last_activity;
44 static Server server;
46 static void Main (string [] args)
48 try {
49 DoMain (args);
50 } catch (Exception ex) {
51 Logger.Log.Error ("Unhandled exception thrown. Exiting immediately.");
52 Logger.Log.Error (ex);
53 Environment.Exit (1);
57 static void DoMain (string [] args)
59 SystemInformation.SetProcessName ("beagled-helper");
61 bool run_by_hand = (Environment.GetEnvironmentVariable ("BEAGLE_RUN_HELPER_BY_HAND") != null);
62 bool log_in_fg = (Environment.GetEnvironmentVariable ("BEAGLE_LOG_IN_THE_FOREGROUND_PLEASE") != null);
64 // FIXME: We always turn on full debugging output! We are still
65 // debugging this code, after all...
66 //bool debug = (Environment.GetEnvironmentVariable ("BEAGLE_DEBUG_FLAG_IS_SET") != null);
68 last_activity = DateTime.Now;
70 Log.Initialize (PathFinder.LogDir,
71 "IndexHelper",
72 //debug ? LogLevel.Debug : LogLevel.Warn,
73 LogLevel.Debug,
74 run_by_hand || log_in_fg);
76 Application.InitCheck ("IndexHelper", ref args);
78 SetupSignalHandlers ();
80 Shutdown.ShutdownEvent += OnShutdown;
82 // Start the server
83 Logger.Log.Debug ("Starting messaging server");
84 bool server_has_been_started = false;
85 try {
86 server = new Server ("socket-helper");
87 server.Start ();
88 server_has_been_started = true;
89 } catch (InvalidOperationException ex) {
90 Logger.Log.Error ("Couldn't start server:");
91 Logger.Log.Error (ex);
94 if (server_has_been_started) {
95 // Set the IO priority to idle so we don't slow down the system
96 if (Environment.GetEnvironmentVariable ("BEAGLE_EXERCISE_THE_DOG") == null)
97 IoPriority.SetIdle ();
99 // Start the monitor thread, which keeps an eye on memory usage and idle time.
100 ExceptionHandlingThread.Start (new ThreadStart (MemoryAndIdleMonitorWorker));
102 // Start a thread that watches the daemon and begins a shutdown
103 // if it terminates.
104 ExceptionHandlingThread.Start (new ThreadStart (DaemonMonitorWorker));
106 Application.Run ();
108 // If we palced our sockets in a temp directory, try to clean it up
109 // Note: this may fail because the daemon is still running
110 if (PathFinder.GetRemoteStorageDir (false) != PathFinder.StorageDir) {
111 try {
112 Directory.Delete (PathFinder.GetRemoteStorageDir (false));
113 } catch (IOException) { }
118 static public void ReportActivity ()
120 last_activity = DateTime.Now;
123 static void MemoryAndIdleMonitorWorker ()
125 int vmrss_original = SystemInformation.VmRss;
127 const double max_idle_time = 30; // minutes
129 const double threshold = 5.0;
130 const int max_request_count = 0;
131 int last_vmrss = 0;
133 while (! Shutdown.ShutdownRequested) {
135 double idle_time;
136 idle_time = (DateTime.Now - last_activity).TotalMinutes;
137 if (idle_time > max_idle_time && RemoteIndexerExecutor.Count > 0) {
138 Logger.Log.Debug ("No activity for {0:0.0} minutes, shutting down", idle_time);
139 Shutdown.BeginShutdown ();
140 return;
143 // Check resident memory usage
144 int vmrss = SystemInformation.VmRss;
145 double size = vmrss / (double) vmrss_original;
146 if (vmrss != last_vmrss)
147 Logger.Log.Debug ("Helper Size: VmRSS={0:0.0} MB, size={1:0.00}, {2:0.0}%",
148 vmrss/1024.0, size, 100.0 * (size - 1) / (threshold - 1));
149 last_vmrss = vmrss;
150 if (size > threshold
151 || (max_request_count > 0 && RemoteIndexerExecutor.Count > max_request_count)) {
152 if (RemoteIndexerExecutor.Count > 0) {
153 Logger.Log.Debug ("Process too big, shutting down!");
154 Shutdown.BeginShutdown ();
155 return;
156 } else {
157 // Paranoia: don't shut down if we haven't done anything yet
158 Logger.Log.Debug ("Deferring shutdown until we've actually done something.");
159 Thread.Sleep (1000);
161 } else {
162 Thread.Sleep (3000);
167 static void DaemonMonitorWorker ()
169 string storage_dir = PathFinder.GetRemoteStorageDir (false);
171 if (storage_dir == null) {
172 Logger.Log.Debug ("The daemon doesn't appear to have started");
173 Logger.Log.Debug ("Shutting down helper.");
174 Shutdown.BeginShutdown ();
175 return;
178 // FIXME: We shouldn't need to know the name of the daemon's socket.
179 string socket_name;
180 socket_name = Path.Combine (storage_dir, "socket");
182 try {
183 SNS.Socket socket;
184 socket = new SNS.Socket (SNS.AddressFamily.Unix, SNS.SocketType.Stream, 0);
185 socket.Connect (new Mono.Unix.UnixEndPoint (socket_name));
187 ArrayList socket_list = new ArrayList ();
189 while (! Shutdown.ShutdownRequested) {
190 socket_list.Add (socket);
191 SNS.Socket.Select (socket_list, null, null, 1000000); // 1000000 microseconds = 1 second
192 if (socket_list.Count != 0) {
193 Logger.Log.Debug ("The daemon appears to have gone away.");
194 Logger.Log.Debug ("Shutting down helper.");
195 Shutdown.BeginShutdown ();
198 } catch (SNS.SocketException) {
199 Logger.Log.Debug ("Caught a SocketException while trying to monitor the daemon");
200 Logger.Log.Debug ("Shutting down");
201 Shutdown.BeginShutdown ();
205 /////////////////////////////////////////////////////////////////////////////
207 static void SetupSignalHandlers ()
209 // Force OurSignalHandler to be JITed
210 OurSignalHandler (-1);
212 // Set up our signal handler
213 Mono.Unix.Native.Stdlib.signal (Mono.Unix.Native.Signum.SIGINT, OurSignalHandler);
214 Mono.Unix.Native.Stdlib.signal (Mono.Unix.Native.Signum.SIGTERM, OurSignalHandler);
215 if (Environment.GetEnvironmentVariable("BEAGLE_THERE_BE_NO_QUITTIN") == null)
216 Mono.Unix.Native.Stdlib.signal (Mono.Unix.Native.Signum.SIGQUIT, OurSignalHandler);
219 // Our handler triggers an orderly shutdown when it receives a signal.
220 // However, this can be annoying if the process gets wedged during
221 // shutdown. To deal with that case, we make a note of the time when
222 // the first signal comes in, and we allow signals to unconditionally
223 // kill the process after 5 seconds have passed.
224 static DateTime signal_time = DateTime.MinValue;
225 static void OurSignalHandler (int signal)
227 // This allows us to call OurSignalHandler w/o doing anything.
228 // We want to call it once to ensure that it is pre-JITed.
229 if (signal < 0)
230 return;
231 Logger.Log.Debug ("Handling signal {0}", signal);
233 bool first_signal = false;
234 if (signal_time == DateTime.MinValue) {
235 signal_time = DateTime.Now;
236 first_signal = true;
239 if (Shutdown.ShutdownRequested) {
241 if (first_signal) {
242 Logger.Log.Debug ("Shutdown already in progress.");
243 } else {
244 double t = (DateTime.Now - signal_time).TotalSeconds;
245 const double min_t = 5;
247 if (t < min_t) {
248 Logger.Log.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t-t);
249 } else {
250 Logger.Log.Debug ("Forcing immediate shutdown.");
251 Environment.Exit (0);
255 } else {
256 Logger.Log.Debug ("Initiating shutdown in response to signal.");
257 Shutdown.BeginShutdown ();
261 static void OnShutdown ()
263 if (server != null)
264 server.Stop ();