1
1
<?php
2
2
// This file is part of BOINC.
3
- // http ://boinc.berkeley.edu
4
- // Copyright (C) 2008 University of California
3
+ // https ://boinc.berkeley.edu
4
+ // Copyright (C) 2024 University of California
5
5
//
6
6
// BOINC is free software; you can redistribute it and/or modify it
7
7
// under the terms of the GNU Lesser General Public License
16
16
// You should have received a copy of the GNU Lesser General Public License
17
17
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
18
18
19
+ // A project can have one or more BOINC databases:
20
+ // DB 0:
21
+ // the main DB; read/write
22
+ // identified in config file by db_host, db_name, db_user, db_passwd
23
+ // db_host defaults to localhost
24
+ // DB 1:
25
+ // read-only replica; identified by
26
+ // replica_db_host/name/user/passwd (must include all)
27
+ // DB 2:
28
+ // read-only replica; identified by
29
+ // replica2_db_host/name/user/passwd (must include all)
30
+ // ... and potentially more
31
+
19
32
function incs () {
20
33
$ d = dirname (__FILE__ );
21
34
require_once ("$ d/db_conn.inc " );
@@ -24,122 +37,102 @@ function incs() {
24
37
25
38
incs ();
26
39
27
- class BoincDb extends DbConn {
28
- static $ instance ;
40
+ // class BoincDb represents a connection to a BOINC database.
41
+ // All its members are static, so there's only 1 connection at a time.
42
+ // get(n) establishes a connection to DB n,
43
+ // or DB 0 if that fails or doesn't exit.
44
+ // close() closes the connection.
29
45
30
- // connect to the database (possibly to a read-only replica)
31
- // NOTE: choice of replica can be made only at the page level.
32
- // If there's a page that's guaranteed to do only reads, put
33
- // BoincDb::get(true);
34
- // at the top of it.
35
- //
36
- // Specify a $fallback_mode that is used when $readonly is true:
37
- // 0: default, use db_user if no replica_db_user is specified,
38
- // first try replica_db_host (if specified) then db_host
39
- // 1: only use replica_db_user, first try replica_db_host then db_host
40
- // 2: only use replica_db_user, only try replica_db_host
41
- // can be set projectwide using <replica_fallback_mode>
46
+ class BoincDb {
47
+ static $ instance ; // a DbConn object, or null
48
+ static $ dbnum ; // which replica we're connected to
49
+
50
+ // connect to DB $dbnum (0, 1, ...)
51
+ // If the requested DB doesn't exist or connection fails, connect to DB 0.
52
+ // Set self::$instance; no return value
42
53
//
43
- static function get_aux ($ readonly , $ fallback_mode = 0 ) {
44
- $ config = get_config ();
45
- $ user = parse_config ($ config , '<db_user> ' );
46
- $ passwd = parse_config ($ config , '<db_passwd> ' );
47
- $ host = parse_config ($ config , '<db_host> ' );
48
- $ replica_host = parse_config ($ config , '<replica_db_host> ' );
49
- $ name = parse_config ($ config , '<db_name> ' );
50
- $ fm = parse_config ($ config , '<replica_fallback_mode> ' );
51
- if ($ fm ) {
52
- // override parameter with config.xml setting
53
- $ fallback_mode = $ fm ;
54
- }
55
- if ($ host == null ) {
56
- $ host = "localhost " ;
57
- }
54
+ static function get_aux ($ dbnum ) {
58
55
$ instance = new DbConn ();
59
- if ($ readonly ) {
60
- if (($ fallback_mode > 0 ) && (!$ replica_host )) {
61
- error_log ("BoincDb::get_aux(): <replica_db_host> required for \$fallback_mode > 0 (giving up) " );
62
- $ instance = null ;
63
- self ::$ instance = $ instance ;
64
- return $ instance ;
65
- }
66
- $ u = parse_config ($ config , '<replica_db_user> ' );
67
- $ p = parse_config ($ config , '<replica_db_passwd> ' );
68
- $ n = parse_config ($ config , '<replica_db_name> ' );
69
- if (($ fallback_mode > 0 ) && (!$ u || !$ p || !$ n )) {
70
- error_log ("BoincDb::get_aux(): <replica_db_*> required for \$fallback_mode > 0 (giving up) " );
71
- $ instance = null ;
72
- self ::$ instance = $ instance ;
73
- return $ instance ;
74
- } else {
75
- // use replica user if given or use normal user for $fallback_mode == 0
76
- if ($ u ) $ user = $ u ;
77
- if ($ p ) $ passwd = $ p ;
78
- if ($ n ) $ name = $ n ;
79
- }
80
- // skip this block if no $replica_host is specified for $fallback_mode == 0
81
- if ($ replica_host ) {
82
- $ retval = $ instance ->init_conn (
83
- $ user , $ passwd , $ replica_host , $ name , true
84
- );
56
+ self ::$ instance = null ;
57
+ $ config = get_config ();
58
+ if ($ dbnum ) {
59
+ $ r = $ dbnum ==1 ?'' :strval ($ dbnum );
60
+ $ host = parse_config ($ config , sprintf ('<replica%s_db_host> ' , $ r ));
61
+ $ name = parse_config ($ config , sprintf ('<replica%s_db_name> ' , $ r ));
62
+ $ user = parse_config ($ config , sprintf ('<replica%s_db_user> ' , $ r ));
63
+ $ passwd = parse_config ($ config , sprintf ('<replica%s_db_passwd> ' , $ r ));
64
+ if ($ host && $ name && $ user && $ passwd ) {
65
+ $ retval = $ instance ->init_conn ($ user , $ passwd , $ host , $ name );
85
66
if ($ retval ) {
86
- // needed for places where we do direct queries
87
- if (!$ instance ->do_query ("use $ name " )) {
88
- error_log ("BoincDb::get_aux(): Couldn't select database $ name on $ replica_host (giving up) " );
89
- $ instance = null ;
90
- }
91
- self ::$ instance = $ instance ;
92
- return $ instance ;
93
- } elseif ($ fallback_mode == 2 ) {
94
- // no fallback to master in this case
95
- error_log ("BoincDb::get_aux(): Couldn't connect to $ user@ $ replica_host (giving up) " );
96
- $ instance = null ;
67
+ //error_log("BoincDb::get_aux(): connected to replica DB $dbnum");
97
68
self ::$ instance = $ instance ;
98
- return $ instance ;
99
- } else {
100
- error_log ("BoincDb::get_aux(): Couldn't connect to $ user@ $ replica_host (trying $ user@ $ host next) " );
69
+ self ::$ dbnum = $ dbnum ;
70
+ return ;
101
71
}
102
72
}
73
+ // if can't connect to replica, fall through and try DB 0
103
74
}
104
- $ retval = $ instance ->init_conn ($ user , $ passwd , $ host , $ name , false );
105
- if (!$ retval ) {
106
- $ instance = null ;
107
- error_log ("BoincDb::get_aux(): Couldn't connect to $ user@ $ host (giving up) " );
108
- } else {
109
- // needed for places where we do direct queries
110
- if (!$ instance ->do_query ("use $ name " )) {
111
- error_log ("BoincDb::get_aux(): Couldn't select database $ name on $ host (giving up) " );
112
- $ instance = null ;
113
- }
75
+ $ host = parse_config ($ config , '<db_host> ' );
76
+ if (!$ host ) $ host = 'localhost ' ;
77
+ $ user = parse_config ($ config , '<db_user> ' );
78
+ $ name = parse_config ($ config , '<db_name> ' );
79
+ $ passwd = parse_config ($ config , '<db_passwd> ' );
80
+ if (!$ name || !$ user || !$ passwd ) {
81
+ error_log ("BoincDb::get_aux(): must specify DB name, user, passwd " );
82
+ return ;
83
+ }
84
+ $ retval = $ instance ->init_conn ($ user , $ passwd , $ host , $ name );
85
+ if ($ retval ) {
86
+ //error_log("BoincDb::get_aux(): connected to DB $dbnum");
87
+ self ::$ instance = $ instance ;
88
+ self ::$ dbnum = 0 ;
89
+ return ;
114
90
}
115
- self ::$ instance = $ instance ;
116
- return $ instance ;
91
+ error_log ("BoincDb::get_aux(): Couldn't connect to DB $ dbnum " );
117
92
}
118
93
119
- // same , but
94
+ // connect to DB $dbnum , but first:
120
95
// 1) check for a cached connection
121
96
// 2) check whether the "stop_web" trigger file is present
122
97
//
123
- static function get ($ readonly = false , $ fallback_mode = 0 ) {
98
+ // If there's a page that's guaranteed to do only reads, put
99
+ // BoincDb::get(true);
100
+ // at the top of it.
101
+ //
102
+ // Note: true == 1.
103
+ // You can also use 2, 3... to select other replicas
104
+ //
105
+ static function get ($ dbnum = 0 ) {
124
106
global $ generating_xml ;
125
- if (!isset (self ::$ instance )) {
126
- if (web_stopped ()) {
127
- if ($ generating_xml ) {
128
- xml_error (-183 , "project down for maintenance " );
129
- } else {
130
- show_project_down ();
131
- }
107
+ if (isset (self ::$ instance )) {
108
+ if (self ::$ dbnum == $ dbnum ) {
109
+ return self ::$ instance ;
132
110
}
133
- self :: get_aux ( $ readonly , $ fallback_mode );
134
- if (! self :: $ instance ) {
135
- if ($ generating_xml ) {
136
- xml_error (- 138 , " Can't connect to database " );
137
- } else {
138
- error_page ( " Can't connect to database " );
139
- }
111
+ close ( );
112
+ }
113
+ if (web_stopped () ) {
114
+ if ( $ generating_xml ) {
115
+ xml_error (- 183 , " project down for maintenance " );
116
+ } else {
117
+ show_project_down ();
140
118
}
141
119
}
142
- return self ::$ instance ;
120
+ self ::get_aux ($ dbnum );
121
+ if (self ::$ instance ) {
122
+ return self ::$ instance ;
123
+ }
124
+ if ($ generating_xml ) {
125
+ xml_error (-138 , "Can't connect to database " );
126
+ } else {
127
+ error_page ("Can't connect to database " );
128
+ }
129
+ }
130
+
131
+ static function close () {
132
+ if (isset (self ::$ instance )) {
133
+ self ::$ instance ->close ();
134
+ self ::$ instance = null ;
135
+ }
143
136
}
144
137
145
138
static function escape_string ($ string ) {
0 commit comments