1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of TokuDB
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     TokuDB is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     TokuDB is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with TokuDB.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ======= */
23 
24 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
25 
26 #ifndef _TOKUDB_BACKGROUND_H
27 #define _TOKUDB_BACKGROUND_H
28 
29 #include "hatoku_hton.h"
30 #include <atomic>
31 #include <list>
32 
33 namespace tokudb {
34 namespace background {
35 
36 class job_manager_t {
37 public:
38     class job_t {
39     public:
40         // NO default constructor
41         job_t() = delete;
42 
43         job_t(bool user_scheduled);
44 
45         virtual ~job_t();
46 
47         // method that runs the job
48         inline void run();
49 
50         // method that tells the job to cancel ASAP
51         inline void cancel();
52 
53         // method that tells the job to clean up/free resources on cancel
54         // or completion
55         inline void destroy();
56 
57         // method that returns a 'key' string for finding a specific job
58         // (or jobs) usually used to find jobs to cancel
59         virtual const char* key() = 0;
60 
61         // method to obtain the database name the job is scheduled on
62         virtual const char* database() = 0;
63 
64         // method to obtain the table name the job is scheduled on
65         virtual const char* table() = 0;
66 
67         // method to obtain the type of job
68         virtual const char* type() = 0;
69 
70         // method to obtain a stringized list of job parameters
71         virtual const char* parameters() = 0;
72 
73         // method to obtain a sting identifying the current status of the job
74         virtual const char* status() = 0;
75 
76         inline bool running() const;
77 
78         inline bool cancelled() const;
79 
80         inline uint64_t id() const;
81 
82         inline bool user_scheduled() const;
83 
84         inline time_t scheduled_time() const;
85 
86         inline time_t started_time() const;
87 
88     protected:
89         // derived classed implement this to actually run their job
on_run()90         virtual void on_run() {};
91 
92         // derived classes implement this to cancel their job
on_cancel()93         virtual void on_cancel() {};
94 
95         // derived classes implement this to clean up/free resources
on_destroy()96         virtual void on_destroy() {};
97 
98     private:
99         static std::atomic<uint64_t> _next_id;
100         std::atomic<bool>   _running;
101         std::atomic<bool>   _cancelled;
102         uint64_t            _id;
103         bool                _user_scheduled;
104         time_t              _scheduled_time;
105         time_t              _started_time;
106     };
107 
108     // pfn for iterate callback
109     typedef void (*pfn_iterate_t)(class job_t*, void*);
110 
111 public:
112     void* operator new(size_t sz);
113     void operator delete(void* p);
114 
115     job_manager_t();
116 
117     ~job_manager_t();
118 
119     // creates/initializes a singleton bjm
120     void initialize();
121 
122     // destroys a bjm singleton
123     // cancels all jobs abd frees all resources
124     void destroy();
125 
126     // schedules or runs a job depending on the 'background' value
127     // job specifics all depend on the implementation od 'job'
128     // background jobs will be executed in a FIFO fashion
129     // two jobs with the same key can not run concurrently
130     // if a foreground job is attempted, any currently scheduled or running
131     // background jobs will be cancelled first
132     // if another foreground job is already running, a new foreground job with
133     // the same key will be rejected
134     bool run_job(job_t* newjob, bool background);
135 
136     // cancels any background job with a matching key
137     bool cancel_job(const char* key);
138 
139     // iterates currently pending and running background jobs, calling
140     // 'callback' with the 'extra' data provided and the original 'extra'
141     // data passed when the job was scheduled
142     void iterate_jobs(pfn_iterate_t callback, void* extra) const;
143 
144     // lock the bjm, this prevents anyone from running, cancelling or iterating
145     // jobs in the bjm.
146     inline void lock();
147     inline void unlock();
148 
149 private:
150     static void* thread_func(void* v);
151 
152     void* real_thread_func();
153 
154     // _mutex MUST be held on entry, will release and reaquire on exit
155     void run(job_t* job);
156 
157     // _mutex MUST be held on entry
158     void cancel(job_t* job);
159 private:
160     typedef std::list<job_t*> jobs_t;
161 
162     mutable tokudb::thread::mutex_t     _mutex;
163     mutable tokudb::thread::semaphore_t _sem;
164     mutable tokudb::thread::thread_t    _thread;
165     jobs_t                              _background_jobs;
166     jobs_t                              _foreground_jobs;
167     std::atomic<bool>                   _shutdown;
168 };
169 
170 extern job_manager_t*    _job_manager;
171 
172 bool initialize();
173 bool destroy();
174 
lock()175 inline void job_manager_t::lock() {
176     assert_debug(!_mutex.is_owned_by_me());
177     mutex_t_lock(_mutex);
178 }
unlock()179 inline void job_manager_t::unlock() {
180     assert_debug(_mutex.is_owned_by_me());
181     mutex_t_unlock(_mutex);
182 }
183 
run()184 inline void job_manager_t::job_t::run() {
185     if (!_cancelled) {
186         _running = true;
187         _started_time = ::time(0);
188         on_run();
189         _running = false;
190     }
191 }
cancel()192 inline void job_manager_t::job_t::cancel() {
193     _cancelled = true;
194     if (_running)
195         on_cancel();
196     while (_running) tokudb::time::sleep_microsec(500000);
197     destroy();
198 }
destroy()199 void job_manager_t::job_t::destroy() {
200     on_destroy();
201 }
running()202 inline bool job_manager_t::job_t::running() const {
203     return _running;
204 }
cancelled()205 inline bool job_manager_t::job_t::cancelled() const {
206     return _cancelled;
207 }
id()208 inline uint64_t job_manager_t::job_t::id() const {
209     return _id;
210 }
user_scheduled()211 inline bool job_manager_t::job_t::user_scheduled() const {
212     return _user_scheduled;
213 }
scheduled_time()214 inline time_t job_manager_t::job_t::scheduled_time() const {
215     return _scheduled_time;
216 }
started_time()217 inline time_t job_manager_t::job_t::started_time() const {
218     return _started_time;
219 }
220 } // namespace background
221 } // namespace tokudb
222 
223 #endif // _TOKUDB_BACKGROUND_H
224