--[[ $%BEGINLICENSE%$ Copyright (C) 2009 MySQL AB, 2009 Sun Microsystems, Inc This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $%ENDLICENSE%$ --]] -- To make query parsing easier local tokenizer = require("proxy.tokenizer") -- To avoid messing with the protocol local proto = assert(require("mysql.proto")) -- To overwrite print() and print to logs require("chassis") -- We assign the value of the same table to itself -- or initialize it if not existent proxy.global.db = proxy.global.db or {} proxy.global.last_node = proxy.global.last_node or 0 -- connection pool if not proxy.global.config.rwsplit then proxy.global.config.rwsplit = { min_idle_connections = 1, max_idle_connections = 1, } end proxy.global.config.rwsplit.is_debug = false --[[ ====================================================================== ]]-- --[[ function connect_server() -- emulate a server proxy.response = { type = proxy.MYSQLD_PACKET_RAW, packets = { proto.to_challenge_packet({ server_status = 2 , server_version = 50132 , thread_id = 12345678922222 }) } } -- You need to specify a nil backend when you start the proxy -- like this: -- proxy-backend-addresses= -- otherwise you get the default 127.0.0.1:3306 if proxy.global.backends[1] == nil then proxy.global.last_node = 1 return proxy.PROXY_SEND_RESULT end ----------------------- local is_debug = proxy.global.config.rwsplit.is_debug -- make sure that we connect to each backend at least ones to -- keep the connections to the servers alive -- -- on read_query we can switch the backends again to another backend if is_debug then print("[connect_server] " .. proxy.connection.client.src.name) print("[connect_server] " .. proxy.connection.client.dst.name) end local rw_ndx = 0 -- init all backends for i = 1, #proxy.global.backends do local s = proxy.global.backends[i] local pool = s.pool -- we don't have a username yet, try to find a connections which is idling local cur_idle = pool.users[""].cur_idle_connections pool.min_idle_connections = proxy.global.config.rwsplit.min_idle_connections pool.max_idle_connections = proxy.global.config.rwsplit.max_idle_connections if is_debug then print(" [".. i .."].connected_clients = " .. s.connected_clients) print(" [".. i .."].pool.cur_idle = " .. cur_idle) print(" [".. i .."].pool.max_idle = " .. pool.max_idle_connections) print(" [".. i .."].pool.min_idle = " .. pool.min_idle_connections) print(" [".. i .."].type = " .. s.type) print(" [".. i .."].state = " .. s.state) end -- prefer connections to the master if s.type == proxy.BACKEND_TYPE_RW and s.state ~= proxy.BACKEND_STATE_DOWN and cur_idle < pool.min_idle_connections then proxy.connection.backend_ndx = i break elseif s.type == proxy.BACKEND_TYPE_RO and s.state ~= proxy.BACKEND_STATE_DOWN and cur_idle < pool.min_idle_connections then proxy.connection.backend_ndx = i break elseif s.type == proxy.BACKEND_TYPE_RW and s.state ~= proxy.BACKEND_STATE_DOWN and rw_ndx == 0 then rw_ndx = i end end if proxy.connection.backend_ndx == 0 then if is_debug then print(" [" .. rw_ndx .. "] taking master as default") end proxy.connection.backend_ndx = rw_ndx end -- pick a random backend -- -- we someone have to skip DOWN backends -- ok, did we got a backend ? if proxy.connection.server then if is_debug then print(" using pooled connection from: " .. proxy.connection.backend_ndx) end -- stay with it return proxy.PROXY_IGNORE_RESULT end if is_debug then print(" [" .. proxy.connection.backend_ndx .. "] idle-conns below min-idle") end -- open a new connection end --]] --[[ ====================================================================== ]]-- function read_query( packet ) -- we use this to send it to the other -- backends query = packet:sub(2) if (string.byte(packet) == proxy.COM_QUIT) or (string.byte(packet) == proxy.COM_INIT_DB) then -- This gets called when you disconnect from the server proxy.response.type = proxy.MYSQLD_PACKET_OK return proxy.PROXY_SEND_RESULT elseif string.byte(packet) ~= proxy.COM_QUERY then proxy.response.type = proxy.MYSQLD_PACKET_OK return proxy.PROXY_SEND_RESULT end end -- End of read_query() --[[ ====================================================================== ]]-- function disconnect_client() local is_debug = proxy.global.config.rwsplit.is_debug if is_debug then print("[disconnect_client] " .. proxy.connection.client.src.name) end -- make sure we are disconnection from the connection -- to move the connection into the pool proxy.connection.backend_ndx = 0 end --[[ ====================================================================== ]]-- --[[ How to use: It supports 5 types of queries mysql> INSERT "key" = "value"; mysql> SELECT "key"; mysql> DELETE "key"; mysql> SELECT *; mysql> DROP; If using in replication, you need to start some connection to create the pool of connections. Yo ucan use something like: $ for i in `seq 1 100` ; do mysql -h127.0.0.1 -P4040 -e "exit"; done ; --]]