private static void MaybeSendSigprof(int rss, long gc) { bool send_sigprof = false; try { if (prev_rss == -1 || prev_gc == -1) { return; } // Log RSS increases of at least 5 megs or 5% if (rss - prev_rss >= 5 * 1024 || (double)rss / (double)prev_rss >= 1.05) { send_sigprof = true; } // Log total object size increase of at least 10%. if ((double)gc / (double)prev_gc >= 1.1) { send_sigprof = true; } } finally { prev_rss = rss; prev_gc = gc; if (send_sigprof) { Log.Debug("Suspicious memory size change detected. Sending SIGPROF to ourself ({0})", sigprof_count++); Mono.Unix.Native.Syscall.kill(System.Diagnostics.Process.GetCurrentProcess().Id, Mono.Unix.Native.Signum.SIGPROF); } } }
private static void HandleSignal(int signal) { Logger.Log.Debug("Handling signal {0} ({1})", signal, (Mono.Unix.Native.Signum)signal); // Pass the signals to the helper too. GLib.Idle.Add(new GLib.IdleHandler(delegate() { RemoteIndexer.SignalRemoteIndexer((Mono.Unix.Native.Signum)signal); return(false); })); // If we get SIGUSR1, turn the debugging level up. if ((Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR1) { LogLevel old_level = Log.Level; Log.Level = LogLevel.Debug; Log.Debug("Moving from log level {0} to Debug", old_level); return; } else if ((Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR2) { // Debugging hook for beagled QueryDriver.DebugHook(); LuceneCommon.DebugHook(); return; } Logger.Log.Debug("Initiating shutdown in response to signal."); Shutdown.BeginShutdown(); }
public static void ReplaceExisting() { Log.Always("Attempting to replace another beagled."); do { ShutdownRequest request = new ShutdownRequest(); Logger.Log.Info("Sending Shutdown"); request.Send(); // Give it a second to shut down the messaging server Thread.Sleep(1000); } while (!StartServer()); }
private static void HandleSignal(int signal) { Log.Warn("Handling signal {0} ({1})", signal, (Mono.Unix.Native.Signum)signal); // If we get SIGUSR1, turn the debugging level up. if ((Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR1) { LogLevel old_level = Log.Level; Log.Level = LogLevel.Debug; Log.Debug("Moving from log level {0} to Debug", old_level); } string span = StringFu.TimeSpanToString(DateTime.Now - last_activity); if (CurrentDisplayUri == null) { Log.Warn("Filtering status ({0} ago): no document is currently being filtered.", span); } else if (CurrentFilter == null) { Log.Warn("Filtering status ({0} ago): determining filter and extracting properties for {1} ({2})", span, CurrentDisplayUri, CurrentContentUri); } else { Log.Warn("Filtering status ({0} ago): extracting text from {1} ({2}) with {3}", span, CurrentDisplayUri, CurrentContentUri, CurrentFilter); } // Don't shut down on information signals (SIGUSR1 and SIGUSR2) if ((Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR1 || (Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR2) { return; } Logger.Log.Debug("Initiating shutdown in response to signal."); Shutdown.BeginShutdown(); }
private static void DoMain(string [] args) { SystemInformation.SetProcessName("beagled-helper"); bool run_by_hand = (Environment.GetEnvironmentVariable("BEAGLE_RUN_HELPER_BY_HAND") != null); bool log_in_fg = (Environment.GetEnvironmentVariable("BEAGLE_LOG_IN_THE_FOREGROUND_PLEASE") != null); bool debug = false, disable_textcache = false; foreach (string arg in args) { if (arg == "--disable-text-cache") { disable_textcache = true; } else if (arg == "--debug") { debug = true; } } last_activity = DateTime.Now; Log.Initialize(PathFinder.LogDir, "IndexHelper", debug ? LogLevel.Debug : LogLevel.Warn, run_by_hand || log_in_fg); Log.Always("Starting Index Helper process (version {0})", ExternalStringsHack.Version); Log.Always("Running on {0}", SystemInformation.MonoRuntimeVersion); Log.Always("Extended attributes are {0}", ExtendedAttribute.Supported ? "supported" : "not supported"); Log.Always("Command Line: {0}", Environment.CommandLine != null ? Environment.CommandLine : "(null)"); if (disable_textcache) { Log.Always("Text cache is disabled."); } // Initialize GObject type system g_type_init(); // Set the IO priority to idle, nice ourselves, and set // a batch scheduling policy so we that we play nice // on the system if (Environment.GetEnvironmentVariable("BEAGLE_EXERCISE_THE_DOG") != null) { Log.Always("BEAGLE_EXERCISE_THE_DOG is set"); } SystemPriorities.ReduceIoPriority(); int nice_to_set; // We set different nice values because the // internal implementation of SCHED_BATCH // unconditionally imposes a +5 penalty on // processes, and we want to be at nice +17, // because it has a nice timeslice. if (SystemPriorities.SetSchedulerPolicyBatch()) { nice_to_set = 12; } else { nice_to_set = 17; } SystemPriorities.Renice(nice_to_set); Server.Init(); #if MONO_1_9 Shutdown.SetupSignalHandlers(new Shutdown.SignalHandler(HandleSignal)); #else SetupSignalHandlers(); #endif Shutdown.ShutdownEvent += OnShutdown; main_loop = new MainLoop(); Shutdown.RegisterMainLoop(main_loop); // Start the server Log.Debug("Starting messaging server"); bool server_has_been_started = false; try { server = new Server("socket-helper", true, false); server.Start(); server_has_been_started = true; } catch (InvalidOperationException ex) { Logger.Log.Error(ex, "Couldn't start server. Exiting immediately."); } if (server_has_been_started) { // Whether we should generate heap-shot snapshots heap_shot = (Environment.GetEnvironmentVariable("_HEY_LETS_DO_A_HEAP_SHOT") != null); if (!run_by_hand) { // Start the monitor thread, which keeps an eye on memory usage and idle time. ExceptionHandlingThread.Start(new ThreadStart(MemoryAndIdleMonitorWorker)); // Start a thread that watches the daemon and begins a shutdown // if it terminates. ExceptionHandlingThread.Start(new ThreadStart(DaemonMonitorWorker)); } // Start the main loop main_loop.Run(); ExceptionHandlingThread.JoinAllThreads(); // If we placed our sockets in a temp directory, try to clean it up // Note: this may fail because the daemon is still running if (PathFinder.GetRemoteStorageDir(false) != PathFinder.StorageDir) { try { Directory.Delete(PathFinder.GetRemoteStorageDir(false)); } catch (IOException) { } } Log.Always("Index helper process shut down cleanly."); } }
private static void MemoryAndIdleMonitorWorker() { int vmrss_original = SystemInformation.VmRss; const double max_idle_time = 30; // minutes const double threshold = 5.0; const int max_request_count = 0; int last_vmrss = 0; while (!Shutdown.ShutdownRequested) { double idle_time; idle_time = (DateTime.Now - last_activity).TotalMinutes; if (idle_time > max_idle_time && RemoteIndexerExecutor.Count > 0) { Logger.Log.Debug("No activity for {0:0.0} minutes, shutting down", idle_time); Shutdown.BeginShutdown(); return; } // Check resident memory usage int vmrss = SystemInformation.VmRss; double size = vmrss / (double)vmrss_original; if (last_vmrss != 0 && vmrss != last_vmrss) { Logger.Log.Debug("Helper Size: VmRSS={0:0.0} MB, size={1:0.00}, {2:0.0}%", vmrss / 1024.0, size, 100.0 * (size - 1) / (threshold - 1)); double increase = vmrss / (double)last_vmrss; if (heap_shot && increase > 1.20) { Log.Debug("Large memory increase detected. Sending SIGPROF to ourself."); Mono.Unix.Native.Syscall.kill(System.Diagnostics.Process.GetCurrentProcess().Id, Mono.Unix.Native.Signum.SIGPROF); } } last_vmrss = vmrss; if (size > threshold || (max_request_count > 0 && RemoteIndexerExecutor.Count > max_request_count)) { if (RemoteIndexerExecutor.Count > 0) { Logger.Log.Debug("Process too big, shutting down!"); Shutdown.BeginShutdown(); return; } else { // Paranoia: don't shut down if we haven't done anything yet Logger.Log.Debug("Deferring shutdown until we've actually done something."); Thread.Sleep(1000); } } else { Thread.Sleep(3000); } } }
public static void DoMain(string[] args) { SystemInformation.InternalCallInitializer.Init(); SystemInformation.SetProcessName("beagled"); // Process the command-line arguments bool arg_debug = false; bool arg_debug_memory = false; bool arg_fg = false; int i = 0; while (i < args.Length) { string arg = args [i]; ++i; string next_arg = i < args.Length ? args [i] : null; switch (arg) { case "-h": case "--help": PrintUsage(); Environment.Exit(0); break; case "--mdb": case "--mono-debug": // Silently ignore these arguments: they get handled // in the wrapper script. break; case "--list-backends": Console.WriteLine("Current available backends:"); Console.Write(QueryDriver.ListBackends()); Environment.Exit(0); break; case "--fg": case "--foreground": arg_fg = true; break; case "--bg": case "--background": arg_fg = false; break; case "--replace": arg_replace = true; break; case "--debug": arg_debug = true; break; case "--heap-shot": arg_heap_shot = true; arg_debug = true; arg_debug_memory = true; break; case "--no-snapshots": case "--no-snapshot": arg_heap_shot_snapshots = false; break; case "--heap-buddy": case "--debug-memory": arg_debug = true; arg_debug_memory = true; break; case "--indexing-test-mode": arg_indexing_test_mode = true; arg_fg = true; break; case "--backend": if (next_arg == null) { Console.WriteLine("--backend requires a backend name"); Environment.Exit(1); break; } if (next_arg.StartsWith("--")) { Console.WriteLine("--backend requires a backend name. Invalid name '{0}'", next_arg); Environment.Exit(1); break; } if (next_arg [0] != '+' && next_arg [0] != '-') { QueryDriver.OnlyAllow(next_arg); } else { if (next_arg [0] == '+') { QueryDriver.Allow(next_arg.Substring(1)); } else { QueryDriver.Deny(next_arg.Substring(1)); } } ++i; // we used next_arg break; case "--add-static-backend": if (next_arg != null) { QueryDriver.AddStaticQueryable(next_arg); } ++i; break; case "--disable-scheduler": arg_disable_scheduler = true; break; case "--indexing-delay": if (next_arg != null) { try { QueryDriver.IndexingDelay = Int32.Parse(next_arg); } catch { Console.WriteLine("'{0}' is not a valid number of seconds", next_arg); Environment.Exit(1); } } ++i; break; case "--autostarted": // FIXME: This option is deprecated and will be removed in a future release. break; case "--disable-text-cache": disable_textcache = true; break; case "--version": VersionFu.PrintVersion(); Environment.Exit(0); break; default: Console.WriteLine("Unknown argument '{0}'", arg); Environment.Exit(1); break; } } if (Environment.GetEnvironmentVariable("SABAYON_SESSION_RUNNING") == "yes") { Console.WriteLine("Beagle is running underneath Sabayon, exiting."); Environment.Exit(0); } if (arg_indexing_test_mode) { LuceneQueryable.OptimizeRightAway = true; } // Bail out if we are trying to run as root if (Environment.UserName == "root" && Environment.GetEnvironmentVariable("SUDO_USER") != null) { Console.WriteLine("You appear to be running beagle using sudo. This can cause problems with"); Console.WriteLine("permissions in your .beagle and .wapi directories if you later try to run"); Console.WriteLine("as an unprivileged user. If you need to run beagle as root, please use"); Console.WriteLine("'su -c' instead."); Environment.Exit(-1); } if (Environment.UserName == "root" && !Conf.Daemon.GetOption(Conf.Names.AllowRoot, false)) { Console.WriteLine("You can not run beagle as root. Beagle is designed to run from your own"); Console.WriteLine("user account. If you want to create multiuser or system-wide indexes, use"); Console.WriteLine("the beagle-build-index tool."); Console.WriteLine(); Console.WriteLine("You can override this setting using the beagle-config or beagle-settings tools."); Environment.Exit(-1); } try { string tmp = PathFinder.HomeDir; } catch (Exception e) { Console.WriteLine("Unable to start the daemon: {0}", e.Message); Environment.Exit(-1); } MainLoopThread = Thread.CurrentThread; Log.Initialize(PathFinder.LogDir, "Beagle", arg_debug ? LogLevel.Debug : LogLevel.Warn, arg_fg); Log.Always("Starting Beagle Daemon (version {0})", ExternalStringsHack.Version); Log.Always("Running on {0}", SystemInformation.MonoRuntimeVersion); Log.Always("Command Line: {0}", Environment.CommandLine != null ? Environment.CommandLine : "(null)"); if (!ExtendedAttribute.Supported) { Logger.Log.Warn("Extended attributes are not supported on this filesystem. " + "Performance will suffer as a result."); } if (disable_textcache) { Log.Warn("Running with text-cache disabled!"); Log.Warn("*** Snippets will not be returned for documents indexed in this session."); } // Check if global configuration files are installed if (!Conf.CheckGlobalConfig()) { Console.WriteLine("Global configuration files not found in '{0}'", PathFinder.ConfigDataDir); Environment.Exit(-1); } // Start our memory-logging thread if (arg_debug_memory) { ExceptionHandlingThread.Start(new ThreadStart(LogMemoryUsage)); } // Do BEAGLE_EXERCISE_THE_DOG_HARDER-related processing. ExerciseTheDogHarder(); // Initialize GObject type system g_type_init(); if (SystemInformation.XssInit()) { Logger.Log.Debug("Established a connection to the X server"); } else { Logger.Log.Debug("Unable to establish a connection to the X server"); } XSetIOErrorHandler(BeagleXIOErrorHandler); // Lower our CPU priority SystemPriorities.Renice(7); QueryDriver.Init(); Server.Init(); #if MONO_1_9 Shutdown.SetupSignalHandlers(new Shutdown.SignalHandler(HandleSignal)); #else SetupSignalHandlers(); #endif Shutdown.ShutdownEvent += OnShutdown; main_loop = new MainLoop(); Shutdown.RegisterMainLoop(main_loop); // Defer all actual startup until the main loop is // running. That way shutdowns during the startup // process work correctly. GLib.Idle.Add(new GLib.IdleHandler(StartupProcess)); // Start our event loop. main_loop.Run(); // We're out of the main loop now, join all the // running threads so we can exit cleanly. ExceptionHandlingThread.JoinAllThreads(); // If we placed our sockets in a temp directory, try to clean it up // Note: this may fail because the helper is still running if (PathFinder.GetRemoteStorageDir(false) != PathFinder.StorageDir) { try { Directory.Delete(PathFinder.GetRemoteStorageDir(false)); } catch (IOException) { } } Log.Always("Beagle daemon process shut down cleanly."); }
public static bool StartupProcess() { // Profile our initialization Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // Fire up our server if (!StartServer()) { if (!arg_replace) { Logger.Log.Error("Could not set up the listener for beagle requests. " + "There is probably another beagled instance running. " + "Use --replace to replace the running service"); Environment.Exit(1); } ReplaceExisting(); } // Set up out-of-process indexing LuceneQueryable.IndexerHook = new LuceneQueryable.IndexerCreator(RemoteIndexer.NewRemoteIndexer); Config config = Conf.Get(Conf.Names.DaemonConfig); // Initialize synchronization to keep the indexes local if PathFinder.StorageDir // is on a non-block device, or if BEAGLE_SYNCHRONIZE_LOCALLY is set if ((!SystemInformation.IsPathOnBlockDevice(PathFinder.StorageDir) && config.GetOption(Conf.Names.IndexSynchronization, true)) || Environment.GetEnvironmentVariable("BEAGLE_SYNCHRONIZE_LOCALLY") != null) { IndexSynchronization.Initialize(); } // Start the query driver. Logger.Log.Debug("Starting QueryDriver"); QueryDriver.Start(); // Start our battery monitor so we can shut down the // scheduler if needed. BatteryMonitor.Init(); bool initially_on_battery = !BatteryMonitor.UsingAC && !config.GetOption(Conf.Names.IndexOnBattery, false); // Start the Global Scheduler thread if (!arg_disable_scheduler) { if (!initially_on_battery) { Logger.Log.Debug("Starting Scheduler thread"); Scheduler.Global.Start(); } else { Log.Debug("Beagle started on battery, not starting scheduler thread"); } } // Start our Inotify threads Inotify.Start(); // Test if the FileAdvise stuff is working: This will print a // warning if not. The actual advice calls will fail silently. FileAdvise.TestAdvise(); #if ENABLE_AVAHI zeroconf = new Beagle.Daemon.Network.Zeroconf(); #endif Conf.WatchForUpdates(); stopwatch.Stop(); Logger.Log.Debug("Daemon initialization finished after {0}", stopwatch); SystemInformation.LogMemoryUsage(); if (arg_indexing_test_mode) { Thread.Sleep(1000); // Ugly paranoia: wait a second for the backends to settle. Logger.Log.Debug("Running in indexing test mode"); Scheduler.Global.EmptyQueueEvent += OnEmptySchedulerQueue; Scheduler.Global.Add(null); // pulse the scheduler } return(false); }