1 // @file background.h 2 3 4 /** 5 * Copyright (C) 2018-present MongoDB, Inc. 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the Server Side Public License, version 1, 9 * as published by MongoDB, Inc. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * Server Side Public License for more details. 15 * 16 * You should have received a copy of the Server Side Public License 17 * along with this program. If not, see 18 * <http://www.mongodb.com/licensing/server-side-public-license>. 19 * 20 * As a special exception, the copyright holders give permission to link the 21 * code of portions of this program with the OpenSSL library under certain 22 * conditions as described in each individual source file and distribute 23 * linked combinations including the program with the OpenSSL library. You 24 * must comply with the Server Side Public License in all respects for 25 * all of the code used other than as permitted herein. If you modify file(s) 26 * with this exception, you may extend this exception to your version of the 27 * file(s), but you are not obligated to do so. If you do not wish to do so, 28 * delete this exception statement from your version. If you delete this 29 * exception statement from all source files in the program, then also delete 30 * it in the license file. 31 */ 32 33 #pragma once 34 35 #include <memory> 36 #include <string> 37 #include <vector> 38 39 #include "mongo/base/disallow_copying.h" 40 #include "mongo/base/status.h" 41 42 namespace mongo { 43 44 /** 45 * Background thread dispatching. 46 * subclass and define run() 47 * 48 * It is not possible to run the job more than once. An attempt to call 'go' while the 49 * task is running will fail. Calling 'go' after the task has finished are ignored and 50 * will not start the job again. 51 * 52 * Thread safety: Note that when the job destructs, the thread is not terminated if still 53 * running. Generally, if the thread could still be running, allocate the job dynamically 54 * and set deleteSelf to true. 55 * 56 * The overridden run() method will be executed on the background thread, so the 57 * BackgroundJob object must exist for as long the background thread is running. 58 */ 59 60 class BackgroundJob { 61 MONGO_DISALLOW_COPYING(BackgroundJob); 62 63 protected: 64 /** 65 * sub-class must instantiate the BackgroundJob 66 * 67 * @param selfDelete if set to true, object will destruct itself after the run() finished 68 * @note selfDelete instances cannot be wait()-ed upon 69 */ 70 explicit BackgroundJob(bool selfDelete = false); 71 72 virtual std::string name() const = 0; 73 74 /** 75 * define this to do your work. 76 * after this returns, state is set to done. 77 * after this returns, deleted if deleteSelf true. 78 * 79 * NOTE: 80 * if run() throws, the exception will be caught within 'this' object and will ultimately lead 81 * to the BackgroundJob's thread being finished, as if run() returned. 82 * 83 */ 84 virtual void run() = 0; 85 86 public: 87 enum State { NotStarted, Running, Done }; 88 89 virtual ~BackgroundJob(); 90 91 /** 92 * starts job. 93 * returns immediately after dispatching. 94 * 95 * @note the BackgroundJob object must live for as long the thread is still running, ie 96 * until getState() returns Done. 97 */ 98 void go(); 99 100 101 /** 102 * If the job has not yet started, transitions the job to the 'done' state immediately, 103 * such that subsequent calls to 'go' are ignored, and notifies any waiters waiting in 104 * 'wait'. If the job has already been started, this method returns a not-ok status: it 105 * does not cancel running jobs. For this reason, you must still call 'wait' on a 106 * BackgroundJob even after calling 'cancel'. 107 */ 108 Status cancel(); 109 110 /** 111 * wait for completion. 112 * 113 * @param msTimeOut maximum amount of time to wait in milliseconds 114 * @return true if did not time out. false otherwise. 115 * 116 * @note you can call wait() more than once if the first call times out. 117 * but you cannot call wait on a self-deleting job. 118 */ 119 bool wait(unsigned msTimeOut = 0); 120 121 // accessors. Note that while the access to the internal state is synchronized within 122 // these methods, there is no guarantee that the BackgroundJob is still in the 123 // indicated state after returning. 124 State getState() const; 125 bool running() const; 126 127 private: 128 const bool _selfDelete; 129 130 struct JobStatus; 131 const std::unique_ptr<JobStatus> _status; 132 133 void jobBody(); 134 }; 135 136 /** 137 * these run "roughly" every minute 138 * instantiate statically 139 * class MyTask : public PeriodicTask { 140 * public: 141 * virtual std::string name() const { return "MyTask; " } 142 * virtual void doWork() { log() << "hi" << std::endl; } 143 * } myTask; 144 */ 145 class PeriodicTask { 146 public: 147 PeriodicTask(); 148 virtual ~PeriodicTask(); 149 150 virtual void taskDoWork() = 0; 151 virtual std::string taskName() const = 0; 152 153 /** 154 * Starts the BackgroundJob that runs PeriodicTasks. You may call this multiple times, 155 * from multiple threads, and the BackgroundJob will be started only once. Please note 156 * that since this method starts threads, it is not appropriate to call it from within 157 * a mongo initializer. Calling this method after calling 'stopRunningPeriodicTasks' 158 * does not re-start the background job. 159 */ 160 static void startRunningPeriodicTasks(); 161 162 /** 163 * Waits 'gracePeriodMillis' for the BackgroundJob responsible for PeriodicTask 164 * execution to finish any running tasks, then destroys it. If the BackgroundJob was 165 * never started, returns Status::OK right away. If the BackgroundJob does not 166 * terminate within the grace period, returns an invalid status. It is safe to call 167 * this method repeatedly from one thread if the grace period is overshot. It is not 168 * safe to call this method from multiple threads, or in a way that races with 169 * 'startRunningPeriodicTasks'. 170 */ 171 static Status stopRunningPeriodicTasks(int gracePeriodMillis); 172 }; 173 174 175 } // namespace mongo 176