Thumbnail file hits. Based on a patch from D Bera
[beagle.git] / beagled / IndexHelper / IndexHelper.cs
blob53f9e8ab995cec06d37473f66395a77971475dda
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 Mono.Posix;
36 using Gtk;
38 using Beagle.Daemon;
39 using Beagle.Util;
41 namespace Beagle.IndexHelper {
43 class IndexHelperTool {
45 static Server server;
47 static void Main (string [] args)
49 bool run_by_hand = (Environment.GetEnvironmentVariable ("BEAGLE_RUN_HELPER_BY_HAND") != null);
50 bool log_in_fg = (Environment.GetEnvironmentVariable ("BEAGLE_LOG_IN_THE_FOREGROUND_PLEASE") != null);
52 Logger.DefaultLevel = LogLevel.Debug;
54 Logger.LogToFile (PathFinder.LogDir, "IndexHelper", run_by_hand || log_in_fg);
56 Application.InitCheck ("IndexHelper", ref args);
58 SetupSignalHandlers ();
60 Shutdown.ShutdownEvent += OnShutdown;
62 // Start the server
63 Logger.Log.Debug ("Starting messaging server");
64 bool server_has_been_started = false;
65 try {
66 server = new Server ("socket-helper");
67 server.Start ();
68 server_has_been_started = true;
69 } catch (InvalidOperationException ex) {
70 Logger.Log.Error ("Couldn't start server:");
71 Logger.Log.Error (ex);
74 if (server_has_been_started) {
75 // Set the IO priority to idle so we don't slow down the system
76 if (Environment.GetEnvironmentVariable ("BEAGLE_EXERCISE_THE_DOG") == null)
77 IoPriority.SetIdle ();
79 // Start the monitor thread, which keeps an eye on memory usage.
80 ExceptionHandlingThread.Start (new ThreadStart (MemoryMonitorWorker));
82 // Start a thread that watches the daemon and begins a shutdown
83 // if it terminates.
84 ExceptionHandlingThread.Start (new ThreadStart (DaemonMonitorWorker));
86 Application.Run ();
88 // If we palced our sockets in a temp directory, try to clean it up
89 // Note: this may fail because the daemon is still running
90 if (PathFinder.GetRemoteStorageDir (false) != PathFinder.StorageDir) {
91 try {
92 Directory.Delete (PathFinder.GetRemoteStorageDir (false));
93 } catch (IOException) { }
97 Environment.Exit (0);
100 static void MemoryMonitorWorker ()
102 int vmrss_original = SystemInformation.VmRss;
103 const double threshold = 5.0;
104 const int max_request_count = 0;
105 int last_vmrss = 0;
107 while (! Shutdown.ShutdownRequested) {
109 // Check resident memory usage
110 int vmrss = SystemInformation.VmRss;
111 double size = vmrss / (double) vmrss_original;
112 if (vmrss != last_vmrss)
113 Logger.Log.Debug ("Helper Size: VmRSS={0:0.0} MB, size={1:0.00}, {2:0.0}%",
114 vmrss/1024.0, size, 100.0 * (size - 1) / (threshold - 1));
115 last_vmrss = vmrss;
116 if (size > threshold
117 || (max_request_count > 0 && RemoteIndexerExecutor.Count > max_request_count)) {
118 if (RemoteIndexerExecutor.Count > 0) {
119 Logger.Log.Debug ("Process too big, shutting down!");
120 Shutdown.BeginShutdown ();
121 } else {
122 // Paranoia: don't shut down if we haven't done anything yet
123 Logger.Log.Debug ("Deferring shutdown until we've actually done something.");
124 Thread.Sleep (250);
126 } else {
127 Thread.Sleep (1000);
132 static void DaemonMonitorWorker ()
134 string storage_dir = PathFinder.GetRemoteStorageDir (false);
136 if (storage_dir == null) {
137 Logger.Log.Debug ("The daemon doesn't appear to have started");
138 Logger.Log.Debug ("Shutting down helper.");
139 Shutdown.BeginShutdown ();
140 return;
143 // FIXME: We shouldn't need to know the name of the daemon's socket.
144 string socket_name;
145 socket_name = Path.Combine (storage_dir, "socket");
147 try {
148 SNS.Socket socket;
149 socket = new SNS.Socket (SNS.AddressFamily.Unix, SNS.SocketType.Stream, 0);
150 socket.Connect (new UnixEndPoint (socket_name));
152 ArrayList socket_list = new ArrayList ();
154 while (! Shutdown.ShutdownRequested) {
155 socket_list.Add (socket);
156 SNS.Socket.Select (socket_list, null, null, 1000000); // 1000000 microseconds = 1 second
157 if (socket_list.Count != 0) {
158 Logger.Log.Debug ("The daemon appears to have gone away.");
159 Logger.Log.Debug ("Shutting down helper.");
160 Shutdown.BeginShutdown ();
163 } catch (SNS.SocketException) {
164 Logger.Log.Debug ("Caught a SocketException while trying to monitor the daemon");
165 Logger.Log.Debug ("Shutting down");
166 Shutdown.BeginShutdown ();
170 /////////////////////////////////////////////////////////////////////////////
172 // The integer values of the Mono.Posix.Signal enumeration don't actually
173 // match the Linux signal numbers of Linux. Oops!
174 // This is fixed in Mono.Unix, but for the moment we want to maintain
175 // compatibility with mono 1.0.x.
176 const int ACTUAL_LINUX_SIGINT = 2;
177 const int ACTUAL_LINUX_SIGQUIT = 3;
178 const int ACTUAL_LINUX_SIGTERM = 15;
180 static void SetupSignalHandlers ()
182 // Force OurSignalHandler to be JITed
183 OurSignalHandler (-1);
185 // Set up our signal handler
186 Mono.Posix.Syscall.sighandler_t sig_handler;
187 sig_handler = new Mono.Posix.Syscall.sighandler_t (OurSignalHandler);
188 Mono.Posix.Syscall.signal (ACTUAL_LINUX_SIGINT, sig_handler);
189 Mono.Posix.Syscall.signal (ACTUAL_LINUX_SIGQUIT, sig_handler);
190 Mono.Posix.Syscall.signal (ACTUAL_LINUX_SIGTERM, sig_handler);
193 // Our handler triggers an orderly shutdown when it receives a signal.
194 // However, this can be annoying if the process gets wedged during
195 // shutdown. To deal with that case, we make a note of the time when
196 // the first signal comes in, and we allow signals to unconditionally
197 // kill the process after 5 seconds have passed.
198 static DateTime signal_time = DateTime.MinValue;
199 static void OurSignalHandler (int signal)
201 // This allows us to call OurSignalHandler w/o doing anything.
202 // We want to call it once to ensure that it is pre-JITed.
203 if (signal < 0)
204 return;
205 Logger.Log.Debug ("Handling signal {0}", signal);
207 bool first_signal = false;
208 if (signal_time == DateTime.MinValue) {
209 signal_time = DateTime.Now;
210 first_signal = true;
213 if (Shutdown.ShutdownRequested) {
215 if (first_signal) {
216 Logger.Log.Debug ("Shutdown already in progress.");
217 } else {
218 double t = (DateTime.Now - signal_time).TotalSeconds;
219 const double min_t = 5;
221 if (t < min_t) {
222 Logger.Log.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t-t);
223 } else {
224 Logger.Log.Debug ("Forcing immediate shutdown.");
225 Environment.Exit (0);
229 } else {
230 Logger.Log.Debug ("Initiating shutdown in response to signal.");
231 Shutdown.BeginShutdown ();
235 static void OnShutdown ()
237 server.Stop ();