예제 #1
0
        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);
                }
            }
        }
예제 #2
0
        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();
        }
예제 #3
0
        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());
        }
예제 #4
0
        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();
        }
예제 #5
0
        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.");
            }
        }
예제 #6
0
        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);
                }
            }
        }
예제 #7
0
        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.");
        }
예제 #8
0
        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);
        }