Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ai
noblogs-wp
Commits
83a36747
Commit
83a36747
authored
Oct 31, 2011
by
shammash
Committed by
lechuck
Sep 20, 2015
Browse files
update hyperdb
parent
3090e580
Changes
1
Hide whitespace changes
Inline
Side-by-side
wp-content/db.php
View file @
83a36747
...
...
@@ -5,7 +5,10 @@
/** Load the wpdb class while preventing instantiation **/
$wpdb
=
true
;
require_once
(
ABSPATH
.
WPINC
.
'/wp-db.php'
);
if
(
defined
(
'WPDB_PATH'
)
)
require_once
(
WPDB_PATH
);
else
require_once
(
ABSPATH
.
WPINC
.
'/wp-db.php'
);
if
(
defined
(
'DB_CONFIG_FILE'
)
&&
file_exists
(
DB_CONFIG_FILE
)
)
{
...
...
@@ -29,6 +32,13 @@ if ( defined('DB_CONFIG_FILE') && file_exists( DB_CONFIG_FILE ) ) {
}
/**
* Common definitions
*/
define
(
'HYPERDB_LAG_OK'
,
1
);
define
(
'HYPERDB_LAG_BEHIND'
,
2
);
define
(
'HYPERDB_LAG_UNKNOWN'
,
3
);
class
hyperdb
extends
wpdb
{
/**
* The last table that was queried
...
...
@@ -144,10 +154,22 @@ class hyperdb extends wpdb {
*/
var
$used_servers
=
array
();
/**
* Whether to save debug_backtrace in save_query_callback. You may wish
* to disable this, e.g. when tracing out-of-memory problems.
*/
var
$save_backtrace
=
true
;
/**
* Maximum lag in seconds. Set null to disable. Requires callbacks.
* @var integer
*/
var
$default_lag_threshold
=
null
;
/**
* Triggers __construct() for backwards compatibility with PHP4
*/
function
db
(
$args
=
null
)
{
function
hyper
db
(
$args
=
null
)
{
return
$this
->
__construct
(
$args
);
}
...
...
@@ -160,6 +182,26 @@ class hyperdb extends wpdb {
foreach
(
get_class_vars
(
__CLASS__
)
as
$var
=>
$value
)
if
(
isset
(
$args
[
$var
])
)
$this
->
$var
=
$args
[
$var
];
$this
->
init_charset
();
}
/**
* Sets $this->charset and $this->collate
*/
function
init_charset
()
{
if
(
function_exists
(
'is_multisite'
)
&&
is_multisite
()
)
{
$this
->
charset
=
'utf8'
;
if
(
defined
(
'DB_COLLATE'
)
&&
DB_COLLATE
)
$this
->
collate
=
DB_COLLATE
;
else
$this
->
collate
=
'utf8_general_ci'
;
}
elseif
(
defined
(
'DB_COLLATE'
)
)
{
$this
->
collate
=
DB_COLLATE
;
}
if
(
defined
(
'DB_CHARSET'
)
)
$this
->
charset
=
DB_CHARSET
;
}
/**
...
...
@@ -171,6 +213,7 @@ class hyperdb extends wpdb {
isset
(
$read
)
or
$read
=
1
;
isset
(
$write
)
or
$write
=
1
;
unset
(
$db
[
'dataset'
]);
if
(
$read
)
$this
->
hyper_servers
[
$dataset
][
'read'
][
$read
][]
=
$db
;
if
(
$write
)
...
...
@@ -185,10 +228,12 @@ class hyperdb extends wpdb {
}
/**
* Add a callback to examine queries and determine dataset.
* Add a callback to a group of callbacks.
* The default group is 'dataset', used to examine
* queries and determine dataset.
*/
function
add_callback
(
$callback
)
{
$this
->
hyper_callbacks
[]
=
$callback
;
function
add_callback
(
$callback
,
$group
=
'dataset'
)
{
$this
->
hyper_callbacks
[
$group
][
]
=
$callback
;
}
/**
...
...
@@ -252,9 +297,8 @@ class hyperdb extends wpdb {
*/
function
is_write_query
(
$q
)
{
// Quick and dirty: only SELECT statements are considered read-only.
$q
=
ltrim
(
$q
,
"
\t
("
);
$word
=
strtoupper
(
substr
(
trim
(
$q
),
0
,
6
)
);
return
'SELECT'
!=
$word
;
$q
=
ltrim
(
$q
,
"
\r\n\t
("
);
return
!
preg_match
(
'/^(?:SELECT|SHOW|DESCRIBE|EXPLAIN)\s/i'
,
$q
);
}
/**
...
...
@@ -265,12 +309,22 @@ class hyperdb extends wpdb {
}
/**
* Callbacks are
specifi
ed in the
config. They must return a dataset
* o
r an associative array wi
th
an
element called 'dataset'
.
* Callbacks are
execut
ed in the
order in which they are registered until one
* o
f them returns something other
than
null
.
*/
function
run_callbacks
(
$query
)
{
$args
=
array
(
$query
,
&
$this
);
foreach
(
$this
->
hyper_callbacks
as
$func
)
{
function
run_callbacks
(
$group
,
$args
=
null
)
{
if
(
!
is_array
(
$this
->
hyper_callbacks
[
$group
]
)
)
return
null
;
if
(
!
isset
(
$args
)
)
{
$args
=
array
(
&
$this
);
}
elseif
(
is_array
(
$args
)
)
{
$args
[]
=
&
$this
;
}
else
{
$args
=
array
(
$args
,
&
$this
);
}
foreach
(
$this
->
hyper_callbacks
[
$group
]
as
$func
)
{
$result
=
call_user_func_array
(
$func
,
$args
);
if
(
isset
(
$result
)
)
return
$result
;
...
...
@@ -315,7 +369,7 @@ class hyperdb extends wpdb {
if
(
isset
(
$this
->
hyper_tables
[
$this
->
table
])
)
{
$dataset
=
$this
->
hyper_tables
[
$this
->
table
];
$this
->
callback_result
=
null
;
}
elseif
(
null
!==
$this
->
callback_result
=
$this
->
run_callbacks
(
$query
)
)
{
}
elseif
(
null
!==
$this
->
callback_result
=
$this
->
run_callbacks
(
'dataset'
,
$query
)
)
{
if
(
is_array
(
$this
->
callback_result
)
)
extract
(
$this
->
callback_result
,
EXTR_OVERWRITE
);
else
...
...
@@ -417,99 +471,176 @@ class hyperdb extends wpdb {
foreach
(
$this
->
hyper_servers
[
$dataset
][
$operation
]
as
$group
=>
$items
)
{
$keys
=
array_keys
(
$items
);
shuffle
(
$keys
);
foreach
(
$keys
as
$key
)
{
foreach
(
$keys
as
$key
)
$servers
[]
=
compact
(
'group'
,
'key'
);
}
}
$tries_remaining
=
count
(
$servers
);
if
(
!
$tries_remaining
)
if
(
!
$tries_remaining
=
count
(
$servers
)
)
return
$this
->
bail
(
"No database servers were found to match the query. (
$this->table
,
$dataset
)"
);
if
(
!
isset
(
$unique_servers
)
)
$unique_servers
=
$tries_remaining
;
}
while
(
$tries_remaining
<
$this
->
min_tries
);
// Connect to a database server
foreach
(
$servers
as
$group_key
)
{
--
$tries_remaining
;
// $group, $key
extract
(
$group_key
,
EXTR_OVERWRITE
);
do
{
$unique_lagged_slaves
=
array
();
$success
=
false
;
// $host, $user, $password, $name, $read, $write [ $connect_function, $timeout ]
extract
(
$this
->
hyper_servers
[
$dataset
][
$operation
][
$group
][
$key
],
EXTR_OVERWRITE
);
foreach
(
$servers
as
$group_key
)
{
--
$tries_remaining
;
// If all servers are lagged, we need to start ignoring the lag and retry
if
(
count
(
$unique_lagged_slaves
)
==
$unique_servers
)
break
;
list
(
$host
,
$port
)
=
explode
(
':'
,
$host
);
// $group, $key
extract
(
$group_key
,
EXTR_OVERWRITE
);
// Split host:port into $host and $port
if
(
strpos
(
$host
,
':'
)
)
list
(
$host
,
$port
)
=
explode
(
':'
,
$host
);
// $host, $user, $password, $name, $read, $write [, $lag_threshold, $connect_function, $timeout ]
extract
(
$this
->
hyper_servers
[
$dataset
][
$operation
][
$group
][
$key
],
EXTR_OVERWRITE
);
// Overlay $server if it was extracted from a callback
if
(
isset
(
$server
)
&&
is_array
(
$server
)
)
extract
(
$server
,
EXTR_OVERWRITE
);
// Split again in case $server had host:port
if
(
strpos
(
$host
,
':'
)
)
list
(
$host
,
$port
)
=
explode
(
':'
,
$host
);
// Make sure there's always a port number
if
(
empty
(
$port
)
)
$port
=
3306
;
// Use a default timeout of 200ms
if
(
!
isset
(
$timeout
)
)
$timeout
=
0.2
;
// Split host:port into $host and $port
if
(
strpos
(
$host
,
':'
)
)
list
(
$host
,
$port
)
=
explode
(
':'
,
$host
);
// Overlay $server if it was extracted from a callback
if
(
isset
(
$server
)
&&
is_array
(
$server
)
)
extract
(
$server
,
EXTR_OVERWRITE
);
// Split again in case $server had host:port
if
(
strpos
(
$host
,
':'
)
)
list
(
$host
,
$port
)
=
explode
(
':'
,
$host
);
// Make sure there's always a port number
if
(
empty
(
$port
)
)
$port
=
3306
;
// Use a default timeout of 200ms
if
(
!
isset
(
$timeout
)
)
$timeout
=
0.2
;
// Get the minimum group here, in case $server rewrites it
if
(
!
isset
(
$min_group
)
||
$min_group
>
$group
)
$min_group
=
$group
;
// Can be used by the lag callbacks
$this
->
lag_cache_key
=
"
$host
:
$port
"
;
$this
->
lag_threshold
=
isset
(
$lag_threshold
)
?
$lag_threshold
:
$this
->
default_lag_threshold
;
// Check for a lagged slave, if applicable
if
(
!
$use_master
&&
!
$write
&&
!
isset
(
$ignore_slave_lag
)
&&
isset
(
$this
->
lag_threshold
)
&&
!
isset
(
$server
[
'host'
]
)
&&
(
$lagged_status
=
$this
->
get_lag_cache
()
)
===
HYPERDB_LAG_BEHIND
)
{
// If it is the last lagged slave and it is with the best preference we will ignore its lag
if
(
!
isset
(
$unique_lagged_slaves
[
"
$host
:
$port
"
]
)
&&
$unique_servers
==
count
(
$unique_lagged_slaves
)
+
1
&&
$group
==
$min_group
)
{
$this
->
lag_threshold
=
null
;
}
else
{
$unique_lagged_slaves
[
"
$host
.
$port
"
]
=
$this
->
lag
;
continue
;
}
}
$this
->
timer_start
();
$this
->
timer_start
();
// Connect if necessary or possible
$tcp
=
null
;
if
(
$use_master
||
!
$tries_remaining
||
!
$this
->
check_tcp_responsiveness
||
true
===
$tcp
=
$this
->
check_tcp_responsiveness
(
$host
,
$port
,
$timeout
)
)
{
$this
->
dbhs
[
$dbhname
]
=
@
$connect_function
(
"
$host
:
$port
"
,
$user
,
$password
,
true
);
}
else
{
$this
->
dbhs
[
$dbhname
]
=
false
;
}
// Connect if necessary or possible
$tcp
=
null
;
if
(
$use_master
||
!
$tries_remaining
||
!
$this
->
check_tcp_responsiveness
||
true
===
$tcp
=
$this
->
check_tcp_responsiveness
(
$host
,
$port
,
$timeout
)
)
{
$this
->
dbhs
[
$dbhname
]
=
@
$connect_function
(
"
$host
:
$port
"
,
$user
,
$password
,
true
);
}
else
{
$this
->
dbhs
[
$dbhname
]
=
false
;
}
$elapsed
=
$this
->
timer_stop
();
$elapsed
=
$this
->
timer_stop
();
if
(
is_resource
(
$this
->
dbhs
[
$dbhname
]
)
)
{
/**
* If we care about lag, disconnect lagged slaves and try to find others.
* We don't disconnect if it is the last lagged slave and it is with the best preference.
*/
if
(
!
$use_master
&&
!
$write
&&
!
isset
(
$ignore_slave_lag
)
&&
isset
(
$this
->
lag_threshold
)
&&
!
isset
(
$server
[
'host'
]
)
&&
$lagged_status
!==
HYPERDB_LAG_OK
&&
(
$lagged_status
=
$this
->
get_lag
()
)
===
HYPERDB_LAG_BEHIND
&&
!
(
!
isset
(
$unique_lagged_slaves
[
"
$host
:
$port
"
]
)
&&
$unique_servers
==
count
(
$unique_lagged_slaves
)
+
1
&&
$group
==
$min_group
)
)
{
$success
=
false
;
$unique_lagged_slaves
[
"
$host
:
$port
"
]
=
$this
->
lag
;
$this
->
disconnect
(
$dbhname
);
$this
->
dbhs
[
$dbhname
]
=
false
;
$msg
=
"Replication lag of
{
$this
->
lag
}
s on
$host
:
$port
(
$dbhname
)"
;
$this
->
print_error
(
$msg
);
continue
;
}
elseif
(
mysql_select_db
(
$name
,
$this
->
dbhs
[
$dbhname
]
)
)
{
$success
=
true
;
$this
->
current_host
=
"
$host
:
$port
"
;
$this
->
dbh2host
[
$dbhname
]
=
"
$host
:
$port
"
;
$queries
=
1
;
$lag
=
isset
(
$this
->
lag
)
?
$this
->
lag
:
0
;
$this
->
last_connection
=
compact
(
'dbhname'
,
'host'
,
'port'
,
'user'
,
'name'
,
'tcp'
,
'elapsed'
,
'success'
,
'querie
s'
,
'lag'
);
$this
->
db_connections
[]
=
$this
->
last_connection
;
$this
->
open_connections
[]
=
$dbhname
;
break
;
}
}
if
(
is_resource
(
$this
->
dbhs
[
$dbhname
])
&&
mysql_select_db
(
$name
,
$this
->
dbhs
[
$dbhname
]
)
)
{
$success
=
true
;
$this
->
current_host
=
"
$host
:
$port
"
;
$this
->
dbh2host
[
$dbhname
]
=
"
$host
:
$port
"
;
$queries
=
1
;
$this
->
last_connection
=
compact
(
'dbhname'
,
'host'
,
'port'
,
'user'
,
'name'
,
'tcp'
,
'elapsed'
,
'success'
,
'queries'
);
$this
->
db_connections
[]
=
$this
->
last_connection
;
$this
->
open_connections
[]
=
$dbhname
;
break
;
}
else
{
$success
=
false
;
$this
->
last_connection
=
compact
(
'dbhname'
,
'host'
,
'port'
,
'user'
,
'name'
,
'tcp'
,
'elapsed'
,
'success'
);
$this
->
db_connections
[]
=
$this
->
last_connection
;
$error_details
=
array
(
'referrer'
=>
"
{
$_SERVER
[
'HTTP_HOST'
]
}{
$_SERVER
[
'REQUEST_URI'
]
}
"
,
'server'
=>
$server
,
$msg
=
date
(
"Y-m-d H:i:s"
)
.
" Can't select
$dbhname
-
\n
"
;
$msg
.
=
"'referrer' => '
{
$_SERVER
[
'HTTP_HOST'
]
}{
$_SERVER
[
'REQUEST_URI'
]
}
',
\n
"
;
$msg
.
=
"'server' =>
{
$server
}
,
\n
"
;
$msg
.
=
"'host' =>
{
$host
}
,
\n
"
;
$msg
.
=
"'error' => "
.
mysql_error
()
.
",
\n
"
;
$msg
.
=
"'errno' => "
.
mysql_errno
()
.
",
\n
"
;
$msg
.
=
"'tcp_responsive' => "
.
(
$tcp
===
true
?
'true'
:
$tcp
)
.
",
\n
"
;
$msg
.
=
"'lagged_status' => "
.
(
isset
(
$lagged_status
)
?
$lagged_status
:
HYPERDB_LAG_UNKNOWN
);
$this
->
print_error
(
$msg
);
}
if
(
!
$success
||
!
isset
(
$this
->
dbhs
[
$dbhname
])
||
!
is_resource
(
$this
->
dbhs
[
$dbhname
]
)
)
{
if
(
!
isset
(
$ignore_slave_lag
)
&&
count
(
$unique_lagged_slaves
)
)
{
// Lagged slaves were not used. Ignore the lag for this connection attempt and retry.
$ignore_slave_lag
=
true
;
$tries_remaining
=
count
(
$servers
);
continue
;
}
$error_details
=
array
(
'host'
=>
$host
,
'error'
=>
mysql_error
(),
'errno'
=>
mysql_errno
(),
'tcp_responsive'
=>
$tcp
===
true
?
'true'
:
$tcp
,
'port'
=>
$port
,
'operation'
=>
$operation
,
'table'
=>
$this
->
table
,
'dataset'
=>
$dataset
,
'dbhname'
=>
$dbhname
);
$msg
=
date
(
"Y-m-d H:i:s"
)
.
" Can't select
$dbhname
- "
;
$msg
.
=
"
\n
"
.
print_r
(
$error_details
,
true
);
$this
->
run_callbacks
(
'db_connection_error'
,
$error_details
);
$this
->
print_error
(
$msg
);
return
$this
->
bail
(
"Unable to connect to
$host
:
$port
to
$operation
table '
$this->table
' (
$dataset
)"
);
}
}
if
(
!
is_resource
(
$this
->
dbhs
[
$dbhname
]
)
)
return
$this
->
bail
(
"Unable to connect to
$host
:
$port
to
$operation
table '
$this->table
' (
$dataset
)"
);
break
;
}
while
(
true
);
$this
->
set_charset
(
$this
->
dbhs
[
$dbhname
],
$charset
,
$collate
);
if
(
!
empty
(
$charset
)
)
$collation_query
=
"SET NAMES '
$charset
'"
;
elseif
(
!
empty
(
$this
->
charset
)
)
$collation_query
=
"SET NAMES '
$this->charset
'"
;
if
(
!
empty
(
$collation_query
)
&&
!
empty
(
$collate
)
)
$collation_query
.
=
" COLLATE '
$collate
'"
;
if
(
!
empty
(
$collation_query
)
&&
!
empty
(
$this
->
collation
)
)
$collation_query
.
=
" COLLATE '
$this->collation
'"
;
mysql_query
(
$collation_query
,
$this
->
dbhs
[
$dbhname
]);
$this
->
dbh
=
$this
->
dbhs
[
$dbhname
];
// needed by $wpdb->_real_escape()
$this
->
last_used_server
=
compact
(
'host'
,
'user'
,
'name'
,
'read'
,
'write'
);
...
...
@@ -524,6 +655,30 @@ class hyperdb extends wpdb {
return
$this
->
dbhs
[
$dbhname
];
}
/**
* Sets the connection's character set.
* @param resource $dbh The resource given by mysql_connect
* @param string $charset The character set (optional)
* @param string $collate The collation (optional)
*/
function
set_charset
(
$dbh
,
$charset
=
null
,
$collate
=
null
)
{
if
(
!
isset
(
$charset
)
)
$charset
=
$this
->
charset
;
if
(
!
isset
(
$collate
)
)
$collate
=
$this
->
collate
;
if
(
$this
->
has_cap
(
'collation'
,
$dbh
)
&&
!
empty
(
$charset
)
)
{
if
(
function_exists
(
'mysql_set_charset'
)
&&
$this
->
has_cap
(
'set_charset'
,
$dbh
)
)
{
mysql_set_charset
(
$charset
,
$dbh
);
$this
->
real_escape
=
true
;
}
else
{
$query
=
$this
->
prepare
(
'SET NAMES %s'
,
$charset
);
if
(
!
empty
(
$collate
)
)
$query
.
=
$this
->
prepare
(
' COLLATE %s'
,
$collate
);
mysql_query
(
$query
,
$dbh
);
}
}
}
/**
* Disconnect and remove connection from open connections list
* @param string $tdbhname
...
...
@@ -595,7 +750,7 @@ class hyperdb extends wpdb {
if
(
$this
->
save_queries
)
{
if
(
is_callable
(
$this
->
save_query_callback
)
)
$this
->
queries
[]
=
call_user_func_array
(
$this
->
save_query_callback
,
array
(
$query
,
$elapsed
,
debug_backtrace
(
)
,
&
$this
)
);
$this
->
queries
[]
=
call_user_func_array
(
$this
->
save_query_callback
,
array
(
$query
,
$elapsed
,
$this
->
save_backtrace
?
debug_backtrace
(
false
)
:
null
,
&
$this
)
);
else
$this
->
queries
[]
=
array
(
$query
,
$elapsed
,
$this
->
get_caller
()
);
}
...
...
@@ -684,7 +839,8 @@ class hyperdb extends wpdb {
case
'group_concat'
:
case
'subqueries'
:
return
version_compare
(
$version
,
'4.1'
,
'>='
);
break
;
case
'set_charset'
:
return
version_compare
(
$version
,
'5.0.7'
,
'>='
);
endswitch
;
return
false
;
...
...
@@ -717,7 +873,7 @@ class hyperdb extends wpdb {
if
(
!
is_callable
(
'debug_backtrace'
)
)
return
''
;
$bt
=
debug_backtrace
();
$bt
=
debug_backtrace
(
false
);
$caller
=
''
;
foreach
(
(
array
)
$bt
as
$trace
)
{
...
...
@@ -746,34 +902,33 @@ class hyperdb extends wpdb {
* @return (bool) true when $host:$post responds within $float_timeout seconds, else (bool) false
*/
function
check_tcp_responsiveness
(
$host
,
$port
,
$float_timeout
)
{
if
(
1
==
2
&&
function_exists
(
'apc_store'
)
)
{
$use_apc
=
true
;
$apc_key
=
"
{
$host
}{
$port
}
"
;
$apc_ttl
=
10
;
}
else
{
$use_apc
=
false
;
}
if
(
$use_apc
)
{
$cached_value
=
apc_fetch
(
$apc_key
);
switch
(
$cached_value
)
{
case
'up'
:
$this
->
tcp_responsive
=
'true'
;
return
true
;
case
'down'
:
$this
->
tcp_responsive
=
'false'
;
return
false
;
}
}
$socket
=
@
fsockopen
(
$host
,
$port
,
$errno
,
$errstr
,
$float_timeout
);
if
(
$socket
===
false
)
{
if
(
$use_apc
)
apc_store
(
$apc_key
,
'down'
,
$apc_ttl
);
$socket
=
@
fsockopen
(
$host
,
$port
,
$errno
,
$errstr
,
$float_timeout
);
if
(
$socket
===
false
)
return
"[ >
$float_timeout
] (
$errno
) '
$errstr
'"
;
}
fclose
(
$socket
);
if
(
$use_apc
)
apc_store
(
$apc_key
,
'up'
,
$apc_ttl
);
return
true
;
return
true
;
}
function
get_lag_cache
()
{
$this
->
lag
=
$this
->
run_callbacks
(
'get_lag_cache'
);
return
$this
->
check_lag
();
}
function
get_lag
()
{
$this
->
lag
=
$this
->
run_callbacks
(
'get_lag'
);
return
$this
->
check_lag
();
}
function
check_lag
()
{
if
(
$this
->
lag
===
false
)
return
HYPERDB_LAG_UNKNOWN
;
if
(
$this
->
lag
>
$this
->
lag_threshold
)
return
HYPERDB_LAG_BEHIND
;
return
HYPERDB_LAG_OK
;
}
// Helper functions for configuration
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment