Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mysql_connect() is pooling non persistent connections. #111

Open
jkbzh opened this issue Oct 16, 2023 · 0 comments
Open

mysql_connect() is pooling non persistent connections. #111

jkbzh opened this issue Oct 16, 2023 · 0 comments

Comments

@jkbzh
Copy link

jkbzh commented Oct 16, 2023

Hello,

Maybe I misunderstood something in the code but it seems the shim is managing a connection pool for non-persistent connections. For persistent connections, it relays on the mysqli extension.

Is this to reproduce behavior from the deprecated mysql extension? If not, why is the shim caching non persistent connections? Would it be unadvisable to switch off this behavior?

From the mysqli doc with respect to persistent connections:

The mysqli extension supports persistent database connections, which are a special kind of pooled connections. By default, every database connection opened by a script is either explicitly closed by the user during runtime or released automatically at the end of the script. A persistent connection is not. Instead it is put into a pool for later reuse, if a connection to the same server using the same username, password, socket, port and default database is opened. Reuse saves connection overhead.

In the shim , for non-persistent connections, mysql_connect() is looking up in a pool if the connection already exists using a hash of the connection characteristics. If it exists, it increases a reference counter and returns the existing connection (lines 66-76), thus making a connection pool:

$hash = sha1($hostname . $username . $flags);
/* persistent connections start with p: */
/* don't use a cached link for those */
if ($hostname[1] !== ':' && isset(MySQL::$connections[$hash])) {
MySQL::$last_connection = MySQL::$connections[$hash]['conn'];
MySQL::$connections[$hash]['refcount'] += 1;
return MySQL::$connections[$hash]['conn'];
}
/* A custom port can be specified by appending the hostname with :{port} e.g. hostname:3307 */
if (preg_match('/^(.+):([\d]+)$/', $hostname, $port_matches) === 1 && $port_matches[1] !== "p") {

Further down in mysql_connect(), the hash is always associated with the connection:

$conn->hash = $hash; // @phpstan-ignore-line
MySQL::$connections[$hash] = array('refcount' => 1, 'conn' => $conn);

$conn->hash = $hash; // @phpstan-ignore-line
MySQL::$connections[$hash] = array('refcount' => 1, 'conn' => $conn);

In mysql_close(), the references to the connection are decreased by one and if the connection has zero references, then it is closed. Again, this is managing a connection pool.

if (isset(MySQL::$connections[$link->hash])) {
MySQL::$connections[$link->hash]['refcount'] -= 1;
}
$return = true;
if (MySQL::$connections[$link->hash]['refcount'] === 0) {
$return = mysqli_close($link);
unset(MySQL::$connections[$link->hash]);
}

Note that there is a potential error in that code as the there is no check to see if the hash exists. I think it should be factorized as:

            if (isset(MySQL::$connections[$link->hash])) {
                MySQL::$connections[$link->hash]['refcount'] -= 1;
                if (MySQL::$connections[$link->hash]['refcount'] === 0) {
                   $return = mysqli_close($link);
                  unset(MySQL::$connections[$link->hash]);
               } else {
                 $return = true;
              }
           }

Thanks for your consideration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant