srv0srv.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:50k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The database server main program
  3. NOTE: SQL Server 7 uses something which the documentation
  4. calls user mode scheduled threads (UMS threads). One such
  5. thread is usually allocated per processor. Win32
  6. documentation does not know any UMS threads, which suggests
  7. that the concept is internal to SQL Server 7. It may mean that
  8. SQL Server 7 does all the scheduling of threads itself, even
  9. in i/o waits. We should maybe modify Innobase to use the same
  10. technique, because thread switches within NT may be too slow.
  11. SQL Server 7 also mentions fibers, which are cooperatively
  12. scheduled threads. They can boost performance by 5 %,
  13. according to the Delaney and Soukup's book.
  14. Windows 2000 will have something called thread pooling
  15. (see msdn website), which we could possibly use.
  16. Another possibility could be to use some very fast user space
  17. thread library. This might confuse NT though.
  18. (c) 1995 Innobase Oy
  19. Created 10/8/1995 Heikki Tuuri
  20. *******************************************************/
  21. #include "srv0srv.h"
  22. #include "ut0mem.h"
  23. #include "os0proc.h"
  24. #include "mem0mem.h"
  25. #include "sync0sync.h"
  26. #include "sync0ipm.h"
  27. #include "thr0loc.h"
  28. #include "com0com.h"
  29. #include "com0shm.h"
  30. #include "que0que.h"
  31. #include "srv0que.h"
  32. #include "log0recv.h"
  33. #include "odbc0odbc.h"
  34. #include "pars0pars.h"
  35. #include "usr0sess.h"
  36. #include "lock0lock.h"
  37. #include "trx0purge.h"
  38. #include "ibuf0ibuf.h"
  39. #include "buf0flu.h"
  40. #include "btr0sea.h"
  41. /* The following counter is incremented whenever there is some user activity
  42. in the server */
  43. ulint srv_activity_count = 0;
  44. /* Server parameters which are read from the initfile */
  45. /* The following three are dir paths which are catenated before file
  46. names, where the file name itself may also contain a path */
  47. char* srv_data_home  = NULL;
  48. char* srv_logs_home  = NULL;
  49. char* srv_arch_dir  = NULL;
  50. ulint srv_n_data_files = 0;
  51. char** srv_data_file_names = NULL;
  52. ulint* srv_data_file_sizes = NULL; /* size in database pages */ 
  53. char** srv_log_group_home_dirs = NULL; 
  54. ulint srv_n_log_groups = ULINT_MAX;
  55. ulint srv_n_log_files = ULINT_MAX;
  56. ulint srv_log_file_size = ULINT_MAX; /* size in database pages */ 
  57. ibool srv_log_archive_on = TRUE;
  58. ulint srv_log_buffer_size = ULINT_MAX; /* size in database pages */ 
  59. ibool srv_flush_log_at_trx_commit = TRUE;
  60. ibool srv_use_native_aio = FALSE;
  61. ulint srv_pool_size = ULINT_MAX; /* size in database pages;
  62. MySQL originally sets this
  63. value in megabytes */ 
  64. ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */ 
  65. ulint srv_lock_table_size = ULINT_MAX;
  66. ulint srv_n_file_io_threads = ULINT_MAX;
  67. ibool srv_archive_recovery = 0;
  68. dulint srv_archive_recovery_limit_lsn;
  69. ulint srv_lock_wait_timeout = 1024 * 1024 * 1024;
  70. /*-------------------------------------------*/
  71. ulint srv_n_spin_wait_rounds = 20;
  72. ulint srv_spin_wait_delay = 5;
  73. ibool srv_priority_boost = TRUE;
  74. char srv_endpoint_name[COM_MAX_ADDR_LEN];
  75. ulint srv_n_com_threads = ULINT_MAX;
  76. ulint srv_n_worker_threads = ULINT_MAX;
  77. ibool srv_print_thread_releases = FALSE;
  78. ibool srv_print_lock_waits = FALSE;
  79. ibool srv_print_buf_io = FALSE;
  80. ibool srv_print_log_io = FALSE;
  81. ibool srv_print_latch_waits = FALSE;
  82. /* The parameters below are obsolete: */
  83. ibool srv_print_parsed_sql = FALSE;
  84. ulint srv_sim_disk_wait_pct = ULINT_MAX;
  85. ulint srv_sim_disk_wait_len = ULINT_MAX;
  86. ibool srv_sim_disk_wait_by_yield = FALSE;
  87. ibool srv_sim_disk_wait_by_wait = FALSE;
  88. ibool srv_measure_contention = FALSE;
  89. ibool srv_measure_by_spin = FALSE;
  90. ibool srv_test_extra_mutexes = FALSE;
  91. ibool srv_test_nocache = FALSE;
  92. ibool srv_test_cache_evict = FALSE;
  93. ibool srv_test_sync = FALSE;
  94. ulint srv_test_n_threads = ULINT_MAX;
  95. ulint srv_test_n_loops = ULINT_MAX;
  96. ulint srv_test_n_free_rnds = ULINT_MAX;
  97. ulint srv_test_n_reserved_rnds = ULINT_MAX;
  98. ulint srv_test_array_size = ULINT_MAX;
  99. ulint srv_test_n_mutexes = ULINT_MAX;
  100. /*
  101. IMPLEMENTATION OF THE SERVER MAIN PROGRAM
  102. =========================================
  103. There is the following analogue between this database
  104. server and an operating system kernel:
  105. DB concept equivalent OS concept
  106. ---------- ---------------------
  107. transaction -- process;
  108. query thread -- thread;
  109. lock -- semaphore;
  110. transaction set to
  111. the rollback state -- kill signal delivered to a process;
  112. kernel -- kernel;
  113. query thread execution:
  114. (a) without kernel mutex
  115. reserved   --  process executing in user mode;
  116. (b) with kernel mutex reserved
  117. -- process executing in kernel mode;
  118. The server is controlled by a master thread which runs at
  119. a priority higher than normal, that is, higher than user threads.
  120. It sleeps most of the time, and wakes up, say, every 300 milliseconds,
  121. to check whether there is anything happening in the server which
  122. requires intervention of the master thread. Such situations may be,
  123. for example, when flushing of dirty blocks is needed in the buffer
  124. pool or old version of database rows have to be cleaned away.
  125. The threads which we call user threads serve the queries of
  126. the clients and input from the console of the server.
  127. They run at normal priority. The server may have several
  128. communications endpoints. A dedicated set of user threads waits
  129. at each of these endpoints ready to receive a client request.
  130. Each request is taken by a single user thread, which then starts
  131. processing and, when the result is ready, sends it to the client
  132. and returns to wait at the same endpoint the thread started from.
  133. So, we do not have dedicated communication threads listening at
  134. the endpoints and dealing the jobs to dedicated worker threads.
  135. Our architecture saves one thread swithch per request, compared
  136. to the solution with dedicated communication threads
  137. which amounts to 15 microseconds on 100 MHz Pentium
  138. running NT. If the client
  139. is communicating over a network, this saving is negligible, but
  140. if the client resides in the same machine, maybe in an SMP machine
  141. on a different processor from the server thread, the saving
  142. can be important as the threads can communicate over shared
  143. memory with an overhead of a few microseconds.
  144. We may later implement a dedicated communication thread solution
  145. for those endpoints which communicate over a network.
  146. Our solution with user threads has two problems: for each endpoint
  147. there has to be a number of listening threads. If there are many
  148. communication endpoints, it may be difficult to set the right number
  149. of concurrent threads in the system, as many of the threads
  150. may always be waiting at less busy endpoints. Another problem
  151. is queuing of the messages, as the server internally does not
  152. offer any queue for jobs.
  153. Another group of user threads is intended for splitting the
  154. queries and processing them in parallel. Let us call these
  155. parallel communication threads. These threads are waiting for
  156. parallelized tasks, suspended on event semaphores.
  157. A single user thread waits for input from the console,
  158. like a command to shut the database.
  159. Utility threads are a different group of threads which takes
  160. care of the buffer pool flushing and other, mainly background
  161. operations, in the server.
  162. Some of these utility threads always run at a lower than normal
  163. priority, so that they are always in background. Some of them
  164. may dynamically boost their priority by the pri_adjust function,
  165. even to higher than normal priority, if their task becomes urgent.
  166. The running of utilities is controlled by high- and low-water marks
  167. of urgency. The urgency may be measured by the number of dirty blocks
  168. in the buffer pool, in the case of the flush thread, for example.
  169. When the high-water mark is exceeded, an utility starts running, until
  170. the urgency drops under the low-water mark. Then the utility thread
  171. suspend itself to wait for an event. The master thread is
  172. responsible of signaling this event when the utility thread is
  173. again needed.
  174. For each individual type of utility, some threads always remain
  175. at lower than normal priority. This is because pri_adjust is implemented
  176. so that the threads at normal or higher priority control their
  177. share of running time by calling sleep. Thus, if the load of the
  178. system sudenly drops, these threads cannot necessarily utilize
  179. the system fully. The background priority threads make up for this,
  180. starting to run when the load drops.
  181. When there is no activity in the system, also the master thread
  182. suspends itself to wait for an event making
  183. the server totally silent. The responsibility to signal this
  184. event is on the user thread which again receives a message
  185. from a client.
  186. There is still one complication in our server design. If a
  187. background utility thread obtains a resource (e.g., mutex) needed by a user
  188. thread, and there is also some other user activity in the system,
  189. the user thread may have to wait indefinitely long for the
  190. resource, as the OS does not schedule a background thread if
  191. there is some other runnable user thread. This problem is called
  192. priority inversion in real-time programming.
  193. One solution to the priority inversion problem would be to
  194. keep record of which thread owns which resource and
  195. in the above case boost the priority of the background thread
  196. so that it will be scheduled and it can release the resource.
  197. This solution is called priority inheritance in real-time programming.
  198. A drawback of this solution is that the overhead of acquiring a mutex 
  199. increases slightly, maybe 0.2 microseconds on a 100 MHz Pentium, because
  200. the thread has to call os_thread_get_curr_id.
  201. This may be compared to 0.5 microsecond overhead for a mutex lock-unlock
  202. pair. Note that the thread
  203. cannot store the information in the resource, say mutex, itself,
  204. because competing threads could wipe out the information if it is
  205. stored before acquiring the mutex, and if it stored afterwards,
  206. the information is outdated for the time of one machine instruction,
  207. at least. (To be precise, the information could be stored to
  208. lock_word in mutex if the machine supports atomic swap.)
  209. The above solution with priority inheritance may become actual in the
  210. future, but at the moment we plan to implement a more coarse solution,
  211. which could be called a global priority inheritance. If a thread
  212. has to wait for a long time, say 300 milliseconds, for a resource,
  213. we just guess that it may be waiting for a resource owned by a background
  214. thread, and boost the the priority of all runnable background threads
  215. to the normal level. The background threads then themselves adjust
  216. their fixed priority back to background after releasing all resources
  217. they had (or, at some fixed points in their program code).
  218. What is the performance of the global priority inheritance solution?
  219. We may weigh the length of the wait time 300 milliseconds, during
  220. which the system processes some other thread
  221. to the cost of boosting the priority of each runnable background
  222. thread, rescheduling it, and lowering the priority again.
  223. On 100 MHz Pentium + NT this overhead may be of the order 100
  224. microseconds per thread. So, if the number of runnable background
  225. threads is not very big, say < 100, the cost is tolerable.
  226. Utility threads probably will access resources used by
  227. user threads not very often, so collisions of user threads
  228. to preempted utility threads should not happen very often.
  229. The thread table contains
  230. information of the current status of each thread existing in the system,
  231. and also the event semaphores used in suspending the master thread
  232. and utility and parallel communication threads when they have nothing to do.
  233. The thread table can be seen as an analogue to the process table
  234. in a traditional Unix implementation.
  235. The thread table is also used in the global priority inheritance
  236. scheme. This brings in one additional complication: threads accessing
  237. the thread table must have at least normal fixed priority,
  238. because the priority inheritance solution does not work if a background
  239. thread is preempted while possessing the mutex protecting the thread table.
  240. So, if a thread accesses the thread table, its priority has to be
  241. boosted at least to normal. This priority requirement can be seen similar to
  242. the privileged mode used when processing the kernel calls in traditional
  243. Unix.*/
  244. /* Thread slot in the thread table */
  245. struct srv_slot_struct{
  246. os_thread_id_t id; /* thread id */
  247. os_thread_t handle; /* thread handle */
  248. ulint type; /* thread type: user, utility etc. */
  249. ibool in_use; /* TRUE if this slot is in use */
  250. ibool suspended; /* TRUE if the thread is waiting
  251. for the event of this slot */
  252. ib_time_t suspend_time; /* time when the thread was
  253. suspended */
  254. os_event_t event; /* event used in suspending the
  255. thread when it has nothing to do */
  256. que_thr_t* thr; /* suspended query thread (only
  257. used for MySQL threads) */
  258. };
  259. /* Table for MySQL threads where they will be suspended to wait for locks */
  260. srv_slot_t* srv_mysql_table = NULL;
  261. os_event_t srv_lock_timeout_thread_event;
  262. srv_sys_t* srv_sys = NULL;
  263. byte srv_pad1[64]; /* padding to prevent other memory update
  264. hotspots from residing on the same memory
  265. cache line */
  266. mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
  267. query threads, and lock table */
  268. byte srv_pad2[64]; /* padding to prevent other memory update
  269. hotspots from residing on the same memory
  270. cache line */
  271. /* The following three values measure the urgency of the jobs of
  272. buffer, version, and insert threads. They may vary from 0 - 1000.
  273. The server mutex protects all these variables. The low-water values
  274. tell that the server can acquiesce the utility when the value
  275. drops below this low-water mark. */
  276. ulint srv_meter[SRV_MASTER + 1];
  277. ulint srv_meter_low_water[SRV_MASTER + 1];
  278. ulint srv_meter_high_water[SRV_MASTER + 1];
  279. ulint srv_meter_high_water2[SRV_MASTER + 1];
  280. ulint srv_meter_foreground[SRV_MASTER + 1];
  281. /* The following values give info about the activity going on in
  282. the database. They are protected by the server mutex. The arrays
  283. are indexed by the type of the thread. */
  284. ulint srv_n_threads_active[SRV_MASTER + 1];
  285. ulint srv_n_threads[SRV_MASTER + 1];
  286. /*************************************************************************
  287. Accessor function to get pointer to n'th slot in the server thread
  288. table. */
  289. static
  290. srv_slot_t*
  291. srv_table_get_nth_slot(
  292. /*===================*/
  293. /* out: pointer to the slot */
  294. ulint index) /* in: index of the slot */
  295. {
  296. ut_a(index < OS_THREAD_MAX_N);
  297. return(srv_sys->threads + index);
  298. }
  299. /*************************************************************************
  300. Gets the number of threads in the system. */
  301. ulint
  302. srv_get_n_threads(void)
  303. /*===================*/
  304. {
  305. ulint i;
  306. ulint n_threads = 0;
  307. mutex_enter(&kernel_mutex);
  308. for (i = SRV_COM; i < SRV_MASTER + 1; i++) {
  309. n_threads += srv_n_threads[i];
  310. }
  311. mutex_exit(&kernel_mutex);
  312. return(n_threads);
  313. }
  314. /*************************************************************************
  315. Reserves a slot in the thread table for the current thread. Also creates the
  316. thread local storage struct for the current thread. NOTE! The server mutex
  317. has to be reserved by the caller! */
  318. static
  319. ulint
  320. srv_table_reserve_slot(
  321. /*===================*/
  322. /* out: reserved slot index */
  323. ulint type) /* in: type of the thread: one of SRV_COM, ... */
  324. {
  325. srv_slot_t* slot;
  326. ulint i;
  327. ut_a(type > 0);
  328. ut_a(type <= SRV_MASTER);
  329. i = 0;
  330. slot = srv_table_get_nth_slot(i);
  331. while (slot->in_use) {
  332. i++;
  333. slot = srv_table_get_nth_slot(i);
  334. }
  335. ut_a(slot->in_use == FALSE);
  336. slot->in_use = TRUE;
  337. slot->suspended = FALSE;
  338. slot->id = os_thread_get_curr_id();
  339. slot->handle = os_thread_get_curr();
  340. slot->type = type;
  341. thr_local_create();
  342. thr_local_set_slot_no(os_thread_get_curr_id(), i);
  343. return(i);
  344. }
  345. /*************************************************************************
  346. Suspends the calling thread to wait for the event in its thread slot.
  347. NOTE! The server mutex has to be reserved by the caller! */
  348. static
  349. os_event_t
  350. srv_suspend_thread(void)
  351. /*====================*/
  352. /* out: event for the calling thread to wait */
  353. {
  354. srv_slot_t* slot;
  355. os_event_t event;
  356. ulint slot_no;
  357. ulint type;
  358. ut_ad(mutex_own(&kernel_mutex));
  359. slot_no = thr_local_get_slot_no(os_thread_get_curr_id());
  360. if (srv_print_thread_releases) {
  361. printf("Suspending thread %lu to slot %lu meter %lun",
  362. os_thread_get_curr_id(), slot_no, srv_meter[SRV_RECOVERY]);
  363. }
  364. slot = srv_table_get_nth_slot(slot_no);
  365. type = slot->type;
  366. ut_ad(type >= SRV_WORKER);
  367. ut_ad(type <= SRV_MASTER);
  368. event = slot->event;
  369. slot->suspended = TRUE;
  370. ut_ad(srv_n_threads_active[type] > 0);
  371. srv_n_threads_active[type]--;
  372. os_event_reset(event);
  373. return(event);
  374. }
  375. /*************************************************************************
  376. Releases threads of the type given from suspension in the thread table.
  377. NOTE! The server mutex has to be reserved by the caller! */
  378. ulint
  379. srv_release_threads(
  380. /*================*/
  381. /* out: number of threads released: this may be
  382. < n if not enough threads were suspended at the
  383. moment */
  384. ulint type, /* in: thread type */
  385. ulint n) /* in: number of threads to release */
  386. {
  387. srv_slot_t* slot;
  388. ulint i;
  389. ulint count = 0;
  390. ut_ad(type >= SRV_WORKER);
  391. ut_ad(type <= SRV_MASTER);
  392. ut_ad(n > 0);
  393. ut_ad(mutex_own(&kernel_mutex));
  394. for (i = 0; i < OS_THREAD_MAX_N; i++) {
  395. slot = srv_table_get_nth_slot(i);
  396. if ((slot->type == type) && slot->suspended) {
  397. slot->suspended = FALSE;
  398. srv_n_threads_active[type]++;
  399. os_event_set(slot->event);
  400. if (srv_print_thread_releases) {
  401. printf(
  402. "Releasing thread %lu type %lu from slot %lu meter %lun",
  403. slot->id, type, i, srv_meter[SRV_RECOVERY]);
  404. }
  405. count++;
  406. if (count == n) {
  407. break;
  408. }
  409. }
  410. }
  411. return(count);
  412. }
  413. /*************************************************************************
  414. Returns the calling thread type. */
  415. ulint
  416. srv_get_thread_type(void)
  417. /*=====================*/
  418. /* out: SRV_COM, ... */
  419. {
  420. ulint slot_no;
  421. srv_slot_t* slot;
  422. ulint type;
  423. mutex_enter(&kernel_mutex);
  424. slot_no = thr_local_get_slot_no(os_thread_get_curr_id());
  425. slot = srv_table_get_nth_slot(slot_no);
  426. type = slot->type;
  427. ut_ad(type >= SRV_WORKER);
  428. ut_ad(type <= SRV_MASTER);
  429. mutex_exit(&kernel_mutex);
  430. return(type);
  431. }
  432. /***********************************************************************
  433. Increments by 1 the count of active threads of the type given
  434. and releases master thread if necessary. */
  435. static
  436. void
  437. srv_inc_thread_count(
  438. /*=================*/
  439. ulint type) /* in: type of the thread */
  440. {
  441. mutex_enter(&kernel_mutex);
  442. srv_activity_count++;
  443. srv_n_threads_active[type]++;
  444. if (srv_n_threads_active[SRV_MASTER] == 0) {
  445. srv_release_threads(SRV_MASTER, 1);
  446. }
  447. mutex_exit(&kernel_mutex);
  448. }
  449. /***********************************************************************
  450. Decrements by 1 the count of active threads of the type given. */
  451. static
  452. void
  453. srv_dec_thread_count(
  454. /*=================*/
  455. ulint type) /* in: type of the thread */
  456. {
  457. mutex_enter(&kernel_mutex);
  458. /* FIXME: the following assertion sometimes fails: */
  459. if (srv_n_threads_active[type] == 0) {
  460. printf("Error: thread type %lun", type);
  461. ut_ad(0);
  462. }
  463. srv_n_threads_active[type]--;
  464. mutex_exit(&kernel_mutex);
  465. }
  466. /***********************************************************************
  467. Calculates the number of allowed utility threads for a thread to decide if
  468. it has to suspend itself in the thread table. */
  469. static
  470. ulint
  471. srv_max_n_utilities(
  472. /*================*/
  473. /* out: maximum number of allowed utilities
  474. of the type given */
  475. ulint type) /* in: utility type */
  476. {
  477. ulint ret;
  478. if (srv_n_threads_active[SRV_COM] == 0) {
  479. if (srv_meter[type] > srv_meter_low_water[type]) {
  480. return(srv_n_threads[type] / 2);
  481. } else {
  482. return(0);
  483. }
  484. } else {
  485. if (srv_meter[type] < srv_meter_foreground[type]) {
  486. return(0);
  487. }
  488. ret = 1 + ((srv_n_threads[type]
  489.      * (ulint)(srv_meter[type] - srv_meter_foreground[type]))
  490.      / (ulint)(1000 - srv_meter_foreground[type]));
  491. if (ret > srv_n_threads[type]) {
  492. return(srv_n_threads[type]);
  493. } else {
  494. return(ret);
  495. }
  496. }
  497. }
  498. /***********************************************************************
  499. Increments the utility meter by the value given and releases utility
  500. threads if necessary. */
  501. void
  502. srv_increment_meter(
  503. /*================*/
  504. ulint type, /* in: utility type */
  505. ulint n) /* in: value to add to meter */
  506. {
  507. ulint m;
  508. mutex_enter(&kernel_mutex);
  509. srv_meter[type] += n;
  510. m = srv_max_n_utilities(type);
  511. if (m > srv_n_threads_active[type]) {
  512. srv_release_threads(type, m - srv_n_threads_active[type]);
  513. }
  514. mutex_exit(&kernel_mutex);
  515. }
  516. /***********************************************************************
  517. Releases max number of utility threads if no queries are active and
  518. the high-water mark for the utility is exceeded. */
  519. void
  520. srv_release_max_if_no_queries(void)
  521. /*===============================*/
  522. {
  523. ulint m;
  524. ulint type;
  525. mutex_enter(&kernel_mutex);
  526. if (srv_n_threads_active[SRV_COM] > 0) {
  527. mutex_exit(&kernel_mutex);
  528. return;
  529. }
  530. type = SRV_RECOVERY;
  531. m = srv_n_threads[type] / 2;
  532. if ((srv_meter[type] > srv_meter_high_water[type])
  533. && (srv_n_threads_active[type] < m)) {
  534. srv_release_threads(type, m - srv_n_threads_active[type]);
  535. printf("Releasing max backgroundn");
  536. }
  537. mutex_exit(&kernel_mutex);
  538. }
  539. /***********************************************************************
  540. Releases one utility thread if no queries are active and
  541. the high-water mark 2 for the utility is exceeded. */
  542. static
  543. void
  544. srv_release_one_if_no_queries(void)
  545. /*===============================*/
  546. {
  547. ulint m;
  548. ulint type;
  549. mutex_enter(&kernel_mutex);
  550. if (srv_n_threads_active[SRV_COM] > 0) {
  551. mutex_exit(&kernel_mutex);
  552. return;
  553. }
  554. type = SRV_RECOVERY;
  555. m = 1;
  556. if ((srv_meter[type] > srv_meter_high_water2[type])
  557.     && (srv_n_threads_active[type] < m)) {
  558. srv_release_threads(type, m - srv_n_threads_active[type]);
  559. printf("Releasing one backgroundn");
  560. }
  561. mutex_exit(&kernel_mutex);
  562. }
  563. #ifdef notdefined
  564. /***********************************************************************
  565. Decrements the utility meter by the value given and suspends the calling
  566. thread, which must be an utility thread of the type given, if necessary. */
  567. static
  568. void
  569. srv_decrement_meter(
  570. /*================*/
  571. ulint type, /* in: utility type */
  572. ulint n) /* in: value to subtract from meter */
  573. {
  574. ulint opt;
  575. os_event_t event;
  576. mutex_enter(&kernel_mutex);
  577. if (srv_meter[type] < n) {
  578. srv_meter[type] = 0;
  579. } else {
  580. srv_meter[type] -= n;
  581. }
  582. opt = srv_max_n_utilities(type);
  583. if (opt < srv_n_threads_active[type]) {
  584.   event = srv_suspend_thread();
  585. mutex_exit(&kernel_mutex);
  586. os_event_wait(event);
  587. } else {
  588. mutex_exit(&kernel_mutex);
  589. }
  590. }
  591. #endif
  592. /*************************************************************************
  593. Implements the server console. */
  594. ulint
  595. srv_console(
  596. /*========*/
  597. /* out: return code, not used */
  598. void* arg) /* in: argument, not used */
  599. {
  600. char command[256];
  601. UT_NOT_USED(arg);
  602. mutex_enter(&kernel_mutex);
  603. srv_table_reserve_slot(SRV_CONSOLE);
  604. mutex_exit(&kernel_mutex);
  605. os_event_wait(srv_sys->operational);
  606. for (;;) {
  607. scanf("%s", command);
  608. srv_inc_thread_count(SRV_CONSOLE);
  609. if (command[0] == 'c') {
  610. printf("Making checkpointn");
  611. log_make_checkpoint_at(ut_dulint_max, TRUE);
  612. printf("Checkpoint completedn");
  613. } else if (command[0] == 'd') {
  614. srv_sim_disk_wait_pct = atoi(command + 1);
  615. printf(
  616. "Starting disk access simulation with pct %lun",
  617. srv_sim_disk_wait_pct);
  618. } else {
  619. printf("nNot supported!n");
  620. }
  621. srv_dec_thread_count(SRV_CONSOLE);
  622. }
  623. return(0);
  624. }
  625. /*************************************************************************
  626. Creates the first communication endpoint for the server. This
  627. first call also initializes the com0com.* module. */
  628. void
  629. srv_communication_init(
  630. /*===================*/
  631. char* endpoint) /* in: server address */
  632. {
  633. ulint ret;
  634. ulint len;
  635. srv_sys->endpoint = com_endpoint_create(COM_SHM);
  636. ut_a(srv_sys->endpoint);
  637. len = ODBC_DATAGRAM_SIZE;
  638. ret = com_endpoint_set_option(srv_sys->endpoint,
  639. COM_OPT_MAX_DGRAM_SIZE,
  640. (byte*)&len, sizeof(ulint));
  641. ut_a(ret == 0);
  642. ret = com_bind(srv_sys->endpoint, endpoint, ut_strlen(endpoint));
  643. ut_a(ret == 0);
  644. }
  645. /*************************************************************************
  646. Implements the recovery utility. */
  647. static
  648. ulint
  649. srv_recovery_thread(
  650. /*================*/
  651. /* out: return code, not used */
  652. void* arg) /* in: not used */
  653. {
  654. ulint slot_no;
  655. os_event_t event;
  656. UT_NOT_USED(arg);
  657. slot_no = srv_table_reserve_slot(SRV_RECOVERY);
  658. os_event_wait(srv_sys->operational);
  659. for (;;) {
  660. /* Finish a possible recovery */
  661. srv_inc_thread_count(SRV_RECOVERY);
  662. /* recv_recovery_from_checkpoint_finish(); */
  663. srv_dec_thread_count(SRV_RECOVERY);
  664. mutex_enter(&kernel_mutex);
  665.   event = srv_suspend_thread();
  666. mutex_exit(&kernel_mutex);
  667. /* Wait for somebody to release this thread; (currently, this
  668. should never be released) */
  669. os_event_wait(event);
  670. }
  671. return(0);
  672. }
  673. /*************************************************************************
  674. Implements the purge utility. */
  675. ulint
  676. srv_purge_thread(
  677. /*=============*/
  678. /* out: return code, not used */
  679. void* arg) /* in: not used */
  680. {
  681. UT_NOT_USED(arg);
  682. os_event_wait(srv_sys->operational);
  683. for (;;) {
  684. trx_purge();
  685. }
  686. return(0);
  687. }
  688. /*************************************************************************
  689. Creates the utility threads. */
  690. void
  691. srv_create_utility_threads(void)
  692. /*============================*/
  693. {
  694. /*      os_thread_t thread;
  695.   os_thread_id_t thr_id; */
  696. ulint i;
  697. mutex_enter(&kernel_mutex);
  698. srv_n_threads[SRV_RECOVERY] = 1;
  699. srv_n_threads_active[SRV_RECOVERY] = 1;
  700. mutex_exit(&kernel_mutex);
  701. for (i = 0; i < 1; i++) {
  702.   /* thread = os_thread_create(srv_recovery_thread, NULL, &thr_id); */
  703.   /* ut_a(thread); */
  704. }
  705. /* thread = os_thread_create(srv_purge_thread, NULL, &thr_id);
  706. ut_a(thread); */
  707. }
  708. /*************************************************************************
  709. Implements the communication threads. */
  710. static
  711. ulint
  712. srv_com_thread(
  713. /*===========*/
  714. /* out: return code; not used */
  715. void* arg) /* in: not used */
  716. {
  717. byte* msg_buf;
  718. byte* addr_buf;
  719. ulint msg_len;
  720. ulint addr_len;
  721. ulint ret;
  722. UT_NOT_USED(arg);
  723. srv_table_reserve_slot(SRV_COM);
  724. os_event_wait(srv_sys->operational);
  725. msg_buf = mem_alloc(com_endpoint_get_max_size(srv_sys->endpoint));
  726. addr_buf = mem_alloc(COM_MAX_ADDR_LEN);
  727. for (;;) {
  728. ret = com_recvfrom(srv_sys->endpoint, msg_buf,
  729. com_endpoint_get_max_size(srv_sys->endpoint),
  730. &msg_len, (char*)addr_buf, COM_MAX_ADDR_LEN,
  731. &addr_len);
  732. ut_a(ret == 0);
  733. srv_inc_thread_count(SRV_COM);
  734. sess_process_cli_msg(msg_buf, msg_len, addr_buf, addr_len);
  735. /* srv_increment_meter(SRV_RECOVERY, 1); */
  736. srv_dec_thread_count(SRV_COM);
  737. /* Release one utility thread for each utility if
  738. high water mark 2 is exceeded and there are no
  739. active queries. This is done to utilize possible
  740. quiet time in the server. */
  741. srv_release_one_if_no_queries();
  742. }
  743. return(0);
  744. }
  745. /*************************************************************************
  746. Creates the communication threads. */
  747. void
  748. srv_create_com_threads(void)
  749. /*========================*/
  750. {
  751.   /* os_thread_t thread;
  752. os_thread_id_t thr_id; */
  753. ulint i;
  754. srv_n_threads[SRV_COM] = srv_n_com_threads;
  755. for (i = 0; i < srv_n_com_threads; i++) {
  756.   /* thread = os_thread_create(srv_com_thread, NULL, &thr_id); */
  757.   /* ut_a(thread); */
  758. }
  759. }
  760. /*************************************************************************
  761. Implements the worker threads. */
  762. static
  763. ulint
  764. srv_worker_thread(
  765. /*==============*/
  766. /* out: return code, not used */
  767. void* arg) /* in: not used */
  768. {
  769. os_event_t event;
  770. UT_NOT_USED(arg);
  771. srv_table_reserve_slot(SRV_WORKER);
  772. os_event_wait(srv_sys->operational);
  773. for (;;) {
  774. mutex_enter(&kernel_mutex);
  775.   event = srv_suspend_thread();
  776. mutex_exit(&kernel_mutex);
  777. /* Wait for somebody to release this thread */
  778. os_event_wait(event);
  779. srv_inc_thread_count(SRV_WORKER);
  780. /* Check in the server task queue if there is work for this
  781. thread, and do the work */
  782. srv_que_task_queue_check();
  783. srv_dec_thread_count(SRV_WORKER);
  784. /* Release one utility thread for each utility if
  785. high water mark 2 is exceeded and there are no
  786. active queries. This is done to utilize possible
  787. quiet time in the server. */
  788. srv_release_one_if_no_queries();
  789. }
  790. return(0);
  791. }
  792. /*************************************************************************
  793. Creates the worker threads. */
  794. void
  795. srv_create_worker_threads(void)
  796. /*===========================*/
  797. {
  798. /* os_thread_t thread;
  799. os_thread_id_t thr_id; */
  800. ulint i;
  801. srv_n_threads[SRV_WORKER] = srv_n_worker_threads;
  802. srv_n_threads_active[SRV_WORKER] = srv_n_worker_threads;
  803. for (i = 0; i < srv_n_worker_threads; i++) {
  804.   /* thread = os_thread_create(srv_worker_thread, NULL, &thr_id); */
  805.   /* ut_a(thread); */
  806. }
  807. }
  808. #ifdef notdefined
  809. /*************************************************************************
  810. Reads a keyword and a value from a file. */
  811. ulint
  812. srv_read_init_val(
  813. /*==============*/
  814. /* out: DB_SUCCESS or error code */
  815. FILE* initfile, /* in: file pointer */
  816. char* keyword, /* in: keyword before value(s), or NULL if
  817. no keyword read */
  818. char* str_buf, /* in/out: buffer for a string value to read,
  819. buffer size must be 10000 bytes, if NULL
  820. then not read */
  821. ulint* num_val, /* out: numerical value to read, if NULL
  822. then not read */
  823. ibool print_not_err) /* in: if TRUE, then we will not print
  824. error messages to console */
  825. {
  826. ulint ret;
  827. char scan_buf[10000];
  828. if (keyword == NULL) {
  829. goto skip_keyword;
  830. }
  831. ret = fscanf(initfile, "%9999s", scan_buf);
  832. if (ret == 0 || ret == EOF || 0 != ut_strcmp(scan_buf, keyword)) {
  833. if (print_not_err) {
  834. return(DB_ERROR);
  835. }
  836. printf("Error in Innobase booting: keyword %s not foundn",
  837. keyword);
  838. printf("from the initfile!n");
  839. return(DB_ERROR);
  840. }
  841. skip_keyword:
  842. if (num_val == NULL && str_buf == NULL) {
  843. return(DB_SUCCESS);
  844. }
  845. ret = fscanf(initfile, "%9999s", scan_buf);
  846. if (ret == EOF || ret == 0) {
  847. if (print_not_err) {
  848. return(DB_ERROR);
  849. }
  850. printf(
  851. "Error in Innobase booting: could not read first value after %sn",
  852. keyword);
  853. printf("from the initfile!n");
  854. return(DB_ERROR);
  855. }
  856. if (str_buf) {
  857. ut_memcpy(str_buf, scan_buf, 10000);
  858. printf("init keyword %s value %s readn", keyword, str_buf);
  859. if (!num_val) {
  860. return(DB_SUCCESS);
  861. }
  862. ret = fscanf(initfile, "%9999s", scan_buf);
  863. if (ret == EOF || ret == 0) {
  864. if (print_not_err) {
  865. return(DB_ERROR);
  866. }
  867. printf(
  868. "Error in Innobase booting: could not read second value after %sn",
  869. keyword);
  870. printf("from the initfile!n");
  871. return(DB_ERROR);
  872. }
  873. }
  874. if (ut_strlen(scan_buf) > 9) {
  875. if (print_not_err) {
  876. return(DB_ERROR);
  877. }
  878. printf(
  879. "Error in Innobase booting: numerical value too big after %sn",
  880. keyword);
  881. printf("in the initfile!n");
  882. return(DB_ERROR);
  883. }
  884. *num_val = (ulint)atoi(scan_buf);
  885. if (*num_val >= 1000000000) {
  886. if (print_not_err) {
  887. return(DB_ERROR);
  888. }
  889. printf(
  890. "Error in Innobase booting: numerical value too big after %sn",
  891. keyword);
  892. printf("in the initfile!n");
  893. return(DB_ERROR);
  894. }
  895. printf("init keyword %s value %lu readn", keyword, *num_val);
  896. return(DB_SUCCESS);
  897. }
  898. /*************************************************************************
  899. Reads keywords and values from an initfile. */
  900. ulint
  901. srv_read_initfile(
  902. /*==============*/
  903. /* out: DB_SUCCESS or error code */
  904. FILE* initfile) /* in: file pointer */
  905. {
  906. char str_buf[10000];
  907. ulint n;
  908. ulint i;
  909. ulint ulint_val;
  910. ulint val1;
  911. ulint val2;
  912. ulint err;
  913. err = srv_read_init_val(initfile, "INNOBASE_DATA_HOME_DIR",
  914. str_buf, NULL, FALSE);
  915. if (err != DB_SUCCESS) return(err);
  916. srv_data_home = ut_malloc(ut_strlen(str_buf) + 1);
  917. ut_memcpy(srv_data_home, str_buf, ut_strlen(str_buf) + 1);
  918. err = srv_read_init_val(initfile,"TABLESPACE_NUMBER_OF_DATA_FILES",
  919. NULL, &n, FALSE);
  920. if (err != DB_SUCCESS) return(err);
  921. srv_n_data_files = n;
  922. srv_data_file_names = ut_malloc(n * sizeof(char*));
  923. srv_data_file_sizes = ut_malloc(n * sizeof(ulint));
  924. for (i = 0; i < n; i++) {
  925. err = srv_read_init_val(initfile,
  926. "DATA_FILE_PATH_AND_SIZE_MB",
  927. str_buf, &ulint_val, FALSE);
  928. if (err != DB_SUCCESS) return(err);
  929. srv_data_file_names[i] = ut_malloc(ut_strlen(str_buf) + 1);
  930. ut_memcpy(srv_data_file_names[i], str_buf,
  931. ut_strlen(str_buf) + 1);
  932. srv_data_file_sizes[i] = ulint_val
  933. * ((1024 * 1024) / UNIV_PAGE_SIZE);
  934. }
  935. err = srv_read_init_val(initfile,
  936. "NUMBER_OF_MIRRORED_LOG_GROUPS", NULL,
  937. &srv_n_log_groups, FALSE);
  938. if (err != DB_SUCCESS) return(err);
  939. err = srv_read_init_val(initfile,
  940. "NUMBER_OF_LOG_FILES_IN_GROUP", NULL,
  941. &srv_n_log_files, FALSE);
  942. if (err != DB_SUCCESS) return(err);
  943. err = srv_read_init_val(initfile, "LOG_FILE_SIZE_KB", NULL,
  944. &srv_log_file_size, FALSE);
  945. if (err != DB_SUCCESS) return(err);
  946. srv_log_file_size = srv_log_file_size / (UNIV_PAGE_SIZE / 1024);
  947. srv_log_group_home_dirs = ut_malloc(srv_n_log_files * sizeof(char*));
  948. for (i = 0; i < srv_n_log_groups; i++) {
  949. err = srv_read_init_val(initfile,
  950. "INNOBASE_LOG_GROUP_HOME_DIR",
  951. str_buf, NULL, FALSE);
  952. if (err != DB_SUCCESS) return(err);
  953. srv_log_group_home_dirs[i] = ut_malloc(ut_strlen(str_buf) + 1);
  954. ut_memcpy(srv_log_group_home_dirs[i], str_buf,
  955. ut_strlen(str_buf) + 1);
  956. }
  957. err = srv_read_init_val(initfile, "INNOBASE_LOG_ARCH_DIR",
  958. str_buf, NULL, FALSE);
  959. if (err != DB_SUCCESS) return(err);
  960. srv_arch_dir = ut_malloc(ut_strlen(str_buf) + 1);
  961. ut_memcpy(srv_arch_dir, str_buf, ut_strlen(str_buf) + 1);
  962. err = srv_read_init_val(initfile, "LOG_ARCHIVE_ON(1/0)", NULL,
  963. &srv_log_archive_on, FALSE);
  964. if (err != DB_SUCCESS) return(err);
  965. err = srv_read_init_val(initfile, "LOG_BUFFER_SIZE_KB", NULL,
  966. &srv_log_buffer_size, FALSE);
  967. if (err != DB_SUCCESS) return(err);
  968. srv_log_buffer_size = srv_log_buffer_size / (UNIV_PAGE_SIZE / 1024);
  969. err = srv_read_init_val(initfile, "FLUSH_LOG_AT_TRX_COMMIT(1/0)", NULL,
  970. &srv_flush_log_at_trx_commit, FALSE);
  971. if (err != DB_SUCCESS) return(err);
  972. err = srv_read_init_val(initfile, "BUFFER_POOL_SIZE_MB", NULL,
  973. &srv_pool_size, FALSE);
  974. if (err != DB_SUCCESS) return(err);
  975. srv_pool_size = srv_pool_size * ((1024 * 1024) / UNIV_PAGE_SIZE);
  976. err = srv_read_init_val(initfile, "ADDITIONAL_MEM_POOL_SIZE_MB", NULL,
  977. &srv_mem_pool_size, FALSE);
  978. if (err != DB_SUCCESS) return(err);
  979. srv_mem_pool_size = srv_mem_pool_size * 1024 * 1024;
  980. srv_lock_table_size = 20 * srv_pool_size;
  981. err = srv_read_init_val(initfile, "NUMBER_OF_FILE_IO_THREADS", NULL,
  982. &srv_n_file_io_threads, FALSE);
  983. if (err != DB_SUCCESS) return(err);
  984. err = srv_read_init_val(initfile, "SRV_RECOVER_FROM_BACKUP",
  985. NULL, NULL, TRUE);
  986. if (err == DB_SUCCESS) {
  987. srv_archive_recovery = TRUE;
  988. srv_archive_recovery_limit_lsn = ut_dulint_max;
  989. err = srv_read_init_val(initfile, NULL, NULL, &val1, TRUE);
  990. err = srv_read_init_val(initfile, NULL, NULL, &val2, TRUE);
  991. if (err == DB_SUCCESS) {
  992. srv_archive_recovery_limit_lsn =
  993. ut_dulint_create(val1, val2);
  994. }
  995. }
  996. /* err = srv_read_init_val(initfile,
  997. "SYNC_NUMBER_OF_SPIN_WAIT_ROUNDS", NULL,
  998. &srv_n_spin_wait_rounds);
  999. err = srv_read_init_val(initfile, "SYNC_SPIN_WAIT_DELAY", NULL,
  1000. &srv_spin_wait_delay); */
  1001. return(DB_SUCCESS);
  1002. }
  1003. /*************************************************************************
  1004. Reads keywords and a values from an initfile. In case of an error, exits
  1005. from the process. */
  1006. void
  1007. srv_read_initfile(
  1008. /*==============*/
  1009. FILE* initfile) /* in: file pointer */
  1010. {
  1011. char str_buf[10000];
  1012. ulint ulint_val;
  1013. srv_read_init_val(initfile, FALSE, "SRV_ENDPOINT_NAME", str_buf,
  1014. &ulint_val);
  1015. ut_a(ut_strlen(str_buf) < COM_MAX_ADDR_LEN);
  1016. ut_memcpy(srv_endpoint_name, str_buf, COM_MAX_ADDR_LEN);
  1017. srv_read_init_val(initfile, TRUE, "SRV_N_COM_THREADS", str_buf,
  1018. &srv_n_com_threads);
  1019. srv_read_init_val(initfile, TRUE, "SRV_N_WORKER_THREADS", str_buf,
  1020. &srv_n_worker_threads);
  1021. srv_read_init_val(initfile, TRUE, "SYNC_N_SPIN_WAIT_ROUNDS", str_buf,
  1022. &srv_n_spin_wait_rounds);
  1023. srv_read_init_val(initfile, TRUE, "SYNC_SPIN_WAIT_DELAY", str_buf,
  1024. &srv_spin_wait_delay);
  1025. srv_read_init_val(initfile, TRUE, "THREAD_PRIORITY_BOOST", str_buf,
  1026. &srv_priority_boost);
  1027. srv_read_init_val(initfile, TRUE, "N_SPACES", str_buf, &srv_n_spaces);
  1028. srv_read_init_val(initfile, TRUE, "N_FILES", str_buf, &srv_n_files);
  1029. srv_read_init_val(initfile, TRUE, "FILE_SIZE", str_buf,
  1030. &srv_file_size);
  1031. srv_read_init_val(initfile, TRUE, "N_LOG_GROUPS", str_buf,
  1032. &srv_n_log_groups);
  1033. srv_read_init_val(initfile, TRUE, "N_LOG_FILES", str_buf,
  1034. &srv_n_log_files);
  1035. srv_read_init_val(initfile, TRUE, "LOG_FILE_SIZE", str_buf,
  1036. &srv_log_file_size);
  1037. srv_read_init_val(initfile, TRUE, "LOG_ARCHIVE_ON", str_buf,
  1038. &srv_log_archive_on);
  1039. srv_read_init_val(initfile, TRUE, "LOG_BUFFER_SIZE", str_buf,
  1040. &srv_log_buffer_size);
  1041. srv_read_init_val(initfile, TRUE, "FLUSH_LOG_AT_TRX_COMMIT", str_buf,
  1042. &srv_flush_log_at_trx_commit);
  1043. srv_read_init_val(initfile, TRUE, "POOL_SIZE", str_buf,
  1044. &srv_pool_size);
  1045. srv_read_init_val(initfile, TRUE, "MEM_POOL_SIZE", str_buf,
  1046. &srv_mem_pool_size);
  1047. srv_read_init_val(initfile, TRUE, "LOCK_TABLE_SIZE", str_buf,
  1048. &srv_lock_table_size);
  1049. srv_read_init_val(initfile, TRUE, "SIM_DISK_WAIT_PCT", str_buf,
  1050. &srv_sim_disk_wait_pct);
  1051. srv_read_init_val(initfile, TRUE, "SIM_DISK_WAIT_LEN", str_buf,
  1052. &srv_sim_disk_wait_len);
  1053. srv_read_init_val(initfile, TRUE, "SIM_DISK_WAIT_BY_YIELD", str_buf,
  1054. &srv_sim_disk_wait_by_yield);
  1055. srv_read_init_val(initfile, TRUE, "SIM_DISK_WAIT_BY_WAIT", str_buf,
  1056. &srv_sim_disk_wait_by_wait);
  1057. srv_read_init_val(initfile, TRUE, "MEASURE_CONTENTION", str_buf,
  1058. &srv_measure_contention);
  1059. srv_read_init_val(initfile, TRUE, "MEASURE_BY_SPIN", str_buf,
  1060. &srv_measure_by_spin);
  1061. srv_read_init_val(initfile, TRUE, "PRINT_THREAD_RELEASES", str_buf,
  1062. &srv_print_thread_releases);
  1063. srv_read_init_val(initfile, TRUE, "PRINT_LOCK_WAITS", str_buf,
  1064. &srv_print_lock_waits);
  1065. if (srv_print_lock_waits) {
  1066. lock_print_waits = TRUE;
  1067. }
  1068. srv_read_init_val(initfile, TRUE, "PRINT_BUF_IO", str_buf,
  1069. &srv_print_buf_io);
  1070. if (srv_print_buf_io) {
  1071. buf_debug_prints = TRUE;
  1072. }
  1073. srv_read_init_val(initfile, TRUE, "PRINT_LOG_IO", str_buf,
  1074. &srv_print_log_io);
  1075. if (srv_print_log_io) {
  1076. log_debug_writes = TRUE;
  1077. }
  1078. srv_read_init_val(initfile, TRUE, "PRINT_PARSED_SQL", str_buf,
  1079. &srv_print_parsed_sql);
  1080. if (srv_print_parsed_sql) {
  1081. pars_print_lexed = TRUE;
  1082. }
  1083. srv_read_init_val(initfile, TRUE, "PRINT_LATCH_WAITS", str_buf,
  1084. &srv_print_latch_waits);
  1085. srv_read_init_val(initfile, TRUE, "TEST_EXTRA_MUTEXES", str_buf,
  1086. &srv_test_extra_mutexes);
  1087. srv_read_init_val(initfile, TRUE, "TEST_NOCACHE", str_buf,
  1088. &srv_test_nocache);
  1089. srv_read_init_val(initfile, TRUE, "TEST_CACHE_EVICT", str_buf,
  1090. &srv_test_cache_evict);
  1091. srv_read_init_val(initfile, TRUE, "TEST_SYNC", str_buf,
  1092. &srv_test_sync);
  1093. srv_read_init_val(initfile, TRUE, "TEST_N_THREADS", str_buf,
  1094. &srv_test_n_threads);
  1095. srv_read_init_val(initfile, TRUE, "TEST_N_LOOPS", str_buf,
  1096. &srv_test_n_loops);
  1097. srv_read_init_val(initfile, TRUE, "TEST_N_FREE_RNDS", str_buf,
  1098. &srv_test_n_free_rnds);
  1099. srv_read_init_val(initfile, TRUE, "TEST_N_RESERVED_RNDS", str_buf,
  1100. &srv_test_n_reserved_rnds);
  1101. srv_read_init_val(initfile, TRUE, "TEST_N_MUTEXES", str_buf,
  1102. &srv_test_n_mutexes);
  1103. srv_read_init_val(initfile, TRUE, "TEST_ARRAY_SIZE", str_buf,
  1104. &srv_test_array_size);
  1105. }
  1106. #endif
  1107. /*************************************************************************
  1108. Initializes the server. */
  1109. static
  1110. void
  1111. srv_init(void)
  1112. /*==========*/
  1113. {
  1114. srv_slot_t* slot;
  1115. ulint i;
  1116. srv_sys = mem_alloc(sizeof(srv_sys_t));
  1117. kernel_mutex_temp = mem_alloc(sizeof(mutex_t));
  1118. mutex_create(&kernel_mutex);
  1119. mutex_set_level(&kernel_mutex, SYNC_KERNEL);
  1120. srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t));
  1121. for (i = 0; i < OS_THREAD_MAX_N; i++) {
  1122. slot = srv_table_get_nth_slot(i);
  1123. slot->in_use = FALSE;
  1124. slot->event = os_event_create(NULL);
  1125. ut_a(slot->event);
  1126. }
  1127. srv_mysql_table = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t));
  1128. for (i = 0; i < OS_THREAD_MAX_N; i++) {
  1129. slot = srv_mysql_table + i;
  1130. slot->in_use = FALSE;
  1131. slot->event = os_event_create(NULL);
  1132. ut_a(slot->event);
  1133. }
  1134. srv_lock_timeout_thread_event = os_event_create(NULL);
  1135. for (i = 0; i < SRV_MASTER + 1; i++) {
  1136. srv_n_threads_active[i] = 0;
  1137. srv_n_threads[i] = 0;
  1138. srv_meter[i] = 30;
  1139. srv_meter_low_water[i] = 50;
  1140. srv_meter_high_water[i] = 100;
  1141. srv_meter_high_water2[i] = 200;
  1142. srv_meter_foreground[i] = 250;
  1143. }
  1144. srv_sys->operational = os_event_create(NULL);
  1145. ut_a(srv_sys->operational);
  1146. UT_LIST_INIT(srv_sys->tasks);
  1147. }
  1148. /*************************************************************************
  1149. Initializes the synchronization primitives, memory system, and the thread
  1150. local storage. */
  1151. static
  1152. void
  1153. srv_general_init(void)
  1154. /*==================*/
  1155. {
  1156. sync_init();
  1157. mem_init(srv_mem_pool_size);
  1158. thr_local_init();
  1159. }
  1160. /*************************************************************************
  1161. Normalizes init parameter values to use units we use inside Innobase. */
  1162. static
  1163. ulint
  1164. srv_normalize_init_values(void)
  1165. /*===========================*/
  1166. /* out: DB_SUCCESS or error code */
  1167. {
  1168. ulint n;
  1169. ulint i;
  1170. n = srv_n_data_files;
  1171. for (i = 0; i < n; i++) {
  1172. srv_data_file_sizes[i] = srv_data_file_sizes[i]
  1173. * ((1024 * 1024) / UNIV_PAGE_SIZE);
  1174. }
  1175. srv_log_file_size = srv_log_file_size / UNIV_PAGE_SIZE;
  1176. srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE;
  1177. srv_pool_size = srv_pool_size / UNIV_PAGE_SIZE;
  1178. srv_lock_table_size = 20 * srv_pool_size;
  1179. return(DB_SUCCESS);
  1180. }
  1181. /*************************************************************************
  1182. Boots the Innobase server. */
  1183. ulint
  1184. srv_boot(void)
  1185. /*==========*/
  1186. /* out: DB_SUCCESS or error code */
  1187. {
  1188. ulint err;
  1189. /* Transform the init parameter values given by MySQL to
  1190. use units we use inside Innobase: */
  1191. err = srv_normalize_init_values();
  1192. if (err != DB_SUCCESS) {
  1193. return(err);
  1194. }
  1195. /* Initialize synchronization primitives, memory management, and thread
  1196. local storage */
  1197. srv_general_init();
  1198. /* Initialize this module */
  1199. srv_init();
  1200. /* Reserve the first slot for the current thread, i.e., the master
  1201. thread */
  1202. srv_table_reserve_slot(SRV_MASTER);
  1203. return(DB_SUCCESS);
  1204. }
  1205. /*************************************************************************
  1206. Reserves a slot in the thread table for the current MySQL OS thread.
  1207. NOTE! The server mutex has to be reserved by the caller! */
  1208. static
  1209. srv_slot_t*
  1210. srv_table_reserve_slot_for_mysql(void)
  1211. /*==================================*/
  1212. /* out: reserved slot */
  1213. {
  1214. srv_slot_t* slot;
  1215. ulint i;
  1216. i = 0;
  1217. slot = srv_mysql_table + i;
  1218. while (slot->in_use) {
  1219. i++;
  1220. ut_a(i < OS_THREAD_MAX_N);
  1221. slot = srv_mysql_table + i;
  1222. }
  1223. ut_a(slot->in_use == FALSE);
  1224. slot->in_use = TRUE;
  1225. slot->id = os_thread_get_curr_id();
  1226. slot->handle = os_thread_get_curr();
  1227. return(slot);
  1228. }
  1229. /*******************************************************************
  1230. Puts a MySQL OS thread to wait for a lock to be released. */
  1231. ibool
  1232. srv_suspend_mysql_thread(
  1233. /*=====================*/
  1234. /* out: TRUE if the lock wait timeout was
  1235. exceeded */
  1236. que_thr_t* thr) /* in: query thread associated with
  1237. the MySQL OS thread */
  1238. {
  1239. srv_slot_t* slot;
  1240. os_event_t event;
  1241. double wait_time;
  1242. ut_ad(!mutex_own(&kernel_mutex));
  1243. os_event_set(srv_lock_timeout_thread_event);
  1244. mutex_enter(&kernel_mutex);
  1245. if (thr->state == QUE_THR_RUNNING) {
  1246. /* The lock has already been released: no need to suspend */
  1247. mutex_exit(&kernel_mutex);
  1248. return(FALSE);
  1249. }
  1250. slot = srv_table_reserve_slot_for_mysql();
  1251. event = slot->event;
  1252. slot->thr = thr;
  1253. os_event_reset(event);
  1254. slot->suspend_time = ut_time();
  1255. /* Wake the lock timeout monitor thread, if it is suspended */
  1256. os_event_set(srv_lock_timeout_thread_event);
  1257. mutex_exit(&kernel_mutex);
  1258. /* Wait for the release */
  1259. os_event_wait(event);
  1260. mutex_enter(&kernel_mutex);
  1261. /* Release the slot for others to use */
  1262. slot->in_use = FALSE;
  1263. wait_time = ut_difftime(ut_time(), slot->suspend_time);
  1264. mutex_exit(&kernel_mutex);
  1265. if (srv_lock_wait_timeout < 100000000 && 
  1266.      wait_time > (double)srv_lock_wait_timeout) {
  1267.     return(TRUE);
  1268. }
  1269. return(FALSE);
  1270. }
  1271. /************************************************************************
  1272. Releases a MySQL OS thread waiting for a lock to be released, if the
  1273. thread is already suspended. */
  1274. void
  1275. srv_release_mysql_thread_if_suspended(
  1276. /*==================================*/
  1277. que_thr_t* thr) /* in: query thread associated with the
  1278. MySQL OS thread  */
  1279. {
  1280. srv_slot_t* slot;
  1281. ulint i;
  1282. ut_ad(mutex_own(&kernel_mutex));
  1283. for (i = 0; i < OS_THREAD_MAX_N; i++) {
  1284. slot = srv_mysql_table + i;
  1285. if (slot->in_use && slot->thr == thr) {
  1286. /* Found */
  1287. os_event_set(slot->event);
  1288. return;
  1289. }
  1290. }
  1291. /* not found */
  1292. }
  1293. /*************************************************************************
  1294. A thread which wakes up threads whose lock wait may have lasted too long. */
  1295. #ifndef __WIN__
  1296. void*
  1297. #else
  1298. ulint
  1299. #endif
  1300. srv_lock_timeout_monitor_thread(
  1301. /*============================*/
  1302. /* out: a dummy parameter */
  1303. void* arg) /* in: a dummy parameter required by
  1304. os_thread_create */
  1305. {
  1306. ibool some_waits;
  1307. srv_slot_t* slot;
  1308. double wait_time;
  1309. ulint i;
  1310. UT_NOT_USED(arg);
  1311. loop:
  1312. /* When someone is waiting for a lock, we wake up every second
  1313. and check if a timeout has passed for a lock wait */
  1314. os_thread_sleep(1000000);
  1315. mutex_enter(&kernel_mutex);
  1316. some_waits = FALSE;
  1317. /* Check of all slots if a thread is waiting there, and if it
  1318. has exceeded the time limit */
  1319. for (i = 0; i < OS_THREAD_MAX_N; i++) {
  1320. slot = srv_mysql_table + i;
  1321. if (slot->in_use) {
  1322. some_waits = TRUE;
  1323. wait_time = ut_difftime(ut_time(), slot->suspend_time);
  1324. if (srv_lock_wait_timeout < 100000000 && 
  1325.      (wait_time > (double) srv_lock_wait_timeout
  1326. || wait_time < 0)) {
  1327. /* Timeout exceeded or a wrap over in system
  1328. time counter: cancel the lock request queued
  1329. by the transaction; NOTE that currently only
  1330. a record lock request can be waiting in
  1331. MySQL! */
  1332. lock_rec_cancel(
  1333.     thr_get_trx(slot->thr)->wait_lock);
  1334. }
  1335. }
  1336. }
  1337. os_event_reset(srv_lock_timeout_thread_event);
  1338. mutex_exit(&kernel_mutex);
  1339. if (some_waits) {
  1340. goto loop;
  1341. }
  1342. /* No one was waiting for a lock: suspend this thread */
  1343. os_event_wait(srv_lock_timeout_thread_event);
  1344. goto loop;
  1345. #ifndef __WIN__
  1346.         return(NULL);
  1347. #else
  1348. return(0);
  1349. #endif
  1350. }
  1351. /***********************************************************************
  1352. Tells the Innobase server that there has been activity in the database
  1353. and wakes up the master thread if it is suspended (not sleeping). Used
  1354. in the MySQL interface. Note that there is a small chance that the master
  1355. thread stays suspended (we do not protect our operation with the kernel
  1356. mutex, for performace reasons). */
  1357. void
  1358. srv_active_wake_master_thread(void)
  1359. /*===============================*/
  1360. {
  1361. srv_activity_count++;
  1362. if (srv_n_threads_active[SRV_MASTER] == 0) {
  1363. mutex_enter(&kernel_mutex);
  1364. srv_release_threads(SRV_MASTER, 1);
  1365. mutex_exit(&kernel_mutex);
  1366. }
  1367. }
  1368. /*************************************************************************
  1369. The master thread controlling the server. */
  1370. #ifndef __WIN__
  1371. void*
  1372. #else
  1373. ulint
  1374. #endif
  1375. srv_master_thread(
  1376. /*==============*/
  1377. /* out: a dummy parameter */
  1378. void* arg) /* in: a dummy parameter required by
  1379. os_thread_create */
  1380. {
  1381. os_event_t event;
  1382. ulint old_activity_count;
  1383. ulint n_pages_purged;
  1384. ulint n_bytes_merged;
  1385. ulint n_pages_flushed;
  1386. ulint n_bytes_archived;
  1387. ulint i;
  1388. UT_NOT_USED(arg);
  1389. srv_table_reserve_slot(SRV_MASTER);
  1390. mutex_enter(&kernel_mutex);
  1391. srv_n_threads_active[SRV_MASTER]++;
  1392. mutex_exit(&kernel_mutex);
  1393. os_event_set(srv_sys->operational);
  1394. loop:
  1395. mutex_enter(&kernel_mutex);
  1396. old_activity_count = srv_activity_count;
  1397. mutex_exit(&kernel_mutex);
  1398. /* We run purge every 10 seconds, even if the server were active: */
  1399. for (i = 0; i < 10; i++) {
  1400. os_thread_sleep(1000000);
  1401. if (srv_activity_count == old_activity_count) {
  1402. if (srv_print_thread_releases) {
  1403. printf("Master thread wakes up!n");
  1404. }
  1405. goto background_loop;
  1406. }
  1407. }
  1408. if (srv_print_thread_releases) {
  1409. printf("Master thread wakes up!n");
  1410. }
  1411. n_pages_purged = 1;
  1412. while (n_pages_purged) {
  1413. n_pages_purged = trx_purge();
  1414. /* TODO: replace this by a check if we are running
  1415. out of file space! */
  1416. }
  1417. background_loop:
  1418. /* In this loop we run background operations while the server
  1419. is quiet */
  1420. mutex_enter(&kernel_mutex);
  1421. if (srv_activity_count != old_activity_count) {
  1422. mutex_exit(&kernel_mutex);
  1423. goto loop;
  1424. }
  1425. old_activity_count = srv_activity_count;
  1426. mutex_exit(&kernel_mutex);
  1427. /* The server has been quiet for a while: start running background
  1428. operations */
  1429. n_pages_purged = trx_purge();
  1430. mutex_enter(&kernel_mutex);
  1431. if (srv_activity_count != old_activity_count) {
  1432. mutex_exit(&kernel_mutex);
  1433. goto loop;
  1434. }
  1435. mutex_exit(&kernel_mutex);
  1436. n_bytes_merged = ibuf_contract(TRUE);
  1437. mutex_enter(&kernel_mutex);
  1438. if (srv_activity_count != old_activity_count) {
  1439. mutex_exit(&kernel_mutex);
  1440. goto loop;
  1441. }
  1442. mutex_exit(&kernel_mutex);
  1443. n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 20, ut_dulint_max);
  1444. mutex_enter(&kernel_mutex);
  1445. if (srv_activity_count != old_activity_count) {
  1446. mutex_exit(&kernel_mutex);
  1447. goto loop;
  1448. }
  1449. mutex_exit(&kernel_mutex);
  1450. buf_flush_wait_batch_end(BUF_FLUSH_LIST);
  1451. log_checkpoint(TRUE, FALSE);
  1452. mutex_enter(&kernel_mutex);
  1453. if (srv_activity_count != old_activity_count) {
  1454. mutex_exit(&kernel_mutex);
  1455. goto loop;
  1456. }
  1457. mutex_exit(&kernel_mutex);
  1458. log_archive_do(FALSE, &n_bytes_archived);
  1459. if (n_pages_purged + n_bytes_merged + n_pages_flushed
  1460. + n_bytes_archived != 0) {
  1461. goto background_loop;
  1462. }
  1463. /* mem_print_new_info();
  1464. fsp_print(0);
  1465. */
  1466. #ifdef UNIV_SEARCH_PERF_STAT
  1467. /* btr_search_print_info(); */
  1468. #endif
  1469. /* There is no work for background operations either: suspend
  1470. master thread to wait for more server activity */
  1471. mutex_enter(&kernel_mutex);
  1472. event = srv_suspend_thread();
  1473. mutex_exit(&kernel_mutex);
  1474. os_event_wait(event);
  1475. goto loop;
  1476. #ifndef __WIN__
  1477.         return(NULL);
  1478. #else
  1479. return(0);
  1480. #endif
  1481. }