diff options
author | DukePyrolator <DukePyrolator@anope.org> | 2013-12-14 09:56:51 +0100 |
---|---|---|
committer | DukePyrolator <DukePyrolator@anope.org> | 2013-12-14 09:56:51 +0100 |
commit | adbc5a0e65ab650b2cd50f518cf9c727ec5fa7b4 (patch) | |
tree | b6f6b93c4ceffaad9a0fbc5fb96df2f47166b5d7 | |
parent | f9a4a0fbeffce294d9f0818fcc02d9dd0f2ec32b (diff) |
irc2sql: improved handling of netsplits
-rw-r--r-- | include/servers.h | 8 | ||||
-rw-r--r-- | modules/stats/irc2sql/irc2sql.cpp | 9 | ||||
-rw-r--r-- | modules/stats/irc2sql/tables.cpp | 100 | ||||
-rw-r--r-- | src/servers.cpp | 7 |
4 files changed, 102 insertions, 22 deletions
diff --git a/include/servers.h b/include/servers.h index 04a174e5b..9a614ae53 100644 --- a/include/servers.h +++ b/include/servers.h @@ -62,7 +62,8 @@ class CoreExport Server : public Extensible bool syncing; /* The server is juped */ bool juped; - + /* The server is about to quit */ + bool quitting; /* Reason this server was quit */ Anope::string quit_reason; @@ -169,6 +170,11 @@ class CoreExport Server : public Extensible */ bool IsJuped() const; + /** Check if the server is quitting + * @return true if this server is quitting. + */ + bool IsQuitting() const; + /** Send a message to alll users on this server * @param source The source of the message * @param message The message diff --git a/modules/stats/irc2sql/irc2sql.cpp b/modules/stats/irc2sql/irc2sql.cpp index 2b3de59e7..d838e6989 100644 --- a/modules/stats/irc2sql/irc2sql.cpp +++ b/modules/stats/irc2sql/irc2sql.cpp @@ -76,9 +76,7 @@ void IRC2SQL::OnServerQuit(Server *server) anope_override if (quitting) return; - query = "UPDATE `" + prefix + "server` " - "SET currentusers = 0, online = 'N', split_time = now() " - "WHERE name = @name@"; + query = "CALL " + prefix + "ServerQuit(@name@)"; query.SetValue("name", server->GetName()); this->RunQuery(query); } @@ -118,7 +116,7 @@ void IRC2SQL::OnUserConnect(User *u, bool &exempt) anope_override void IRC2SQL::OnUserQuit(User *u, const Anope::string &msg) anope_override { - if (quitting) + if (quitting || u->server->IsQuitting()) return; query = "CALL " + prefix + "UserQuit(@nick@)"; @@ -238,9 +236,8 @@ void IRC2SQL::OnLeaveChannel(User *u, Channel *c) anope_override * user is quitting, we already received a OnUserQuit() * at this point the user is already removed from SQL and all channels */ - if (u->Quitting()); + if (u->Quitting()) return; - query = "CALL " + prefix + "PartUser(@nick@,@channel@)"; query.SetValue("nick", u->nick); query.SetValue("channel", c->name); diff --git a/modules/stats/irc2sql/tables.cpp b/modules/stats/irc2sql/tables.cpp index 5bbdf9252..890720587 100644 --- a/modules/stats/irc2sql/tables.cpp +++ b/modules/stats/irc2sql/tables.cpp @@ -7,12 +7,12 @@ void IRC2SQL::CheckTables() if (firstrun) { /* - * drop/recreate some tables in case anope crashed - * and was unable to clear the content (ison) + * reset some tables to make sure they are really empty */ - this->sql->RunQuery(SQL::Query("DROP TABLE " + prefix + "user")); - this->sql->RunQuery(SQL::Query("DROP TABLE " + prefix + "chan")); - this->sql->RunQuery(SQL::Query("DROP TABLE " + prefix + "ison")); + this->sql->RunQuery("TRUNCATE TABLE " + prefix + "user"); + this->sql->RunQuery("TRUNCATE TABLE " + prefix + "chan"); + this->sql->RunQuery("TRUNCATE TABLE " + prefix + "ison"); + this->sql->RunQuery("UPDATE `" + prefix + "server` SET currentusers=0, online='N'"); } this->GetTables(); @@ -227,8 +227,80 @@ void IRC2SQL::CheckTables() "END"; this->RunQuery(query); + if (this->HasProcedure(prefix + "ServerQuit")) + this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "ServerQuit")); + query = "CREATE PROCEDURE " + prefix + "ServerQuit(sname_ varchar(255)) " + "BEGIN " + /* 1. + * loop through all channels and decrease the user count + * by the number of users that are on this channel AND + * on the splitting server + * + * we dont have to care about channels that get empty, there will be + * an extra OnChannelDelete event triggered from anope. + */ + "DECLARE no_more_rows BOOLEAN DEFAULT FALSE;" + "DECLARE channel_ varchar(255);" + "DECLARE ucount_ int;" + "DECLARE channel_cursor CURSOR FOR " + "SELECT c.channel " + "FROM `" + prefix + "chan` as c, `" + prefix + "ison` as i, " + "`" + prefix + "user` as u, `" + prefix + "server` as s " + "WHERE c.chanid = i.chanid " + "AND i.nickid = u.nickid " + "AND u.servid = s.id " + "AND s.name = sname_;" + "DECLARE CONTINUE HANDLER FOR NOT FOUND " + "SET no_more_rows = TRUE;" + "OPEN channel_cursor;" + "the_loop: LOOP " + "FETCH channel_cursor INTO channel_;" + "IF no_more_rows THEN " + "CLOSE channel_cursor;" + "LEAVE the_loop;" + "END IF;" + "SELECT COUNT(*) INTO ucount_ " + "FROM `" + prefix + "ison` AS i, `" + prefix + "chan` AS c," + "`" + prefix + "user` AS u, `" + prefix + "server` AS s " + "WHERE i.nickid = u.nickid " + "AND u.servid = s.id " + "AND i.chanid = c.chanid " + "AND c.channel = channel_ " + "AND s.name = sname_; " + "UPDATE `" + prefix + "chan` " + "SET currentusers = currentusers - ucount_ " + "WHERE channel = channel_;" + "END LOOP;" + + /* 2. + * remove all users on the splitting server from the ison table + */ + "DELETE i FROM `" + prefix + "ison` AS i " + "INNER JOIN `" + prefix + "server` AS s " + "INNER JOIN `" + prefix + "user` AS u " + "WHERE i.nickid = u.nickid " + "AND u.servid = s.id " + "AND s.name = sname_;" + + /* 3. + * remove all users on the splitting server from the user table + */ + "DELETE u FROM `" + prefix + "user` AS u " + "INNER JOIN `" + prefix + "server` AS s " + "WHERE s.id = u.servid " + "AND s.name = sname_;" + + /* 4. + * on the splitting server, set usercount = 0, split_time = now(), online = 'N' + */ + "UPDATE `" + prefix + "server` SET currentusers = 0, split_time = now(), online = 'N' " + "WHERE name = sname_;" + "END;"; // end of the procedure + this->RunQuery(query); + + if (this->HasProcedure(prefix + "UserQuit")) - this->RunQuery(SQL::Query("DROP PROCEDURE " +prefix + "UserQuit")); + this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "UserQuit")); query = "CREATE PROCEDURE `" + prefix + "UserQuit`" "(nick_ varchar(255)) " "BEGIN " @@ -245,10 +317,8 @@ void IRC2SQL::CheckTables() /* remove from all channels where the user was on */ "DELETE i FROM `" + prefix + "ison` AS i " "INNER JOIN `" + prefix + "user` as u " - "INNER JOIN `" + prefix + "chan` as c " "WHERE u.nick = nick_ " "AND i.nickid = u.nickid " - "AND i.chanid = c.chanid;" /* remove the user from the user table */ "DELETE FROM `" + prefix + "user` WHERE nick = nick_; " "END"; @@ -298,13 +368,13 @@ void IRC2SQL::CheckTables() query = "CREATE PROCEDURE `" + prefix + "PartUser`" "(nick_ varchar(255), channel_ varchar(255)) " "BEGIN " - "DELETE FROM `" + prefix + "ison` " - "USING `" + prefix + "ison`, `" + prefix + "user` , `" - + prefix + "chan` " - "WHERE " + prefix + "ison.nickid = " + prefix + "user.nickid " - "AND " + prefix + "user.nick = nick_ " - "AND " + prefix + "ison.chanid = " + prefix + "chan.chanid " - "AND " + prefix + "chan.channel = channel_; " + "DELETE i FROM `" + prefix + "ison` AS i " + "INNER JOIN `" + prefix + "user` AS u " + "INNER JOIN `" + prefix + "chan` AS c " + "WHERE i.nickid = u.nickid " + "AND u.nick = nick_ " + "AND i.chanid = c.chanid " + "AND c.channel = channel_;" "UPDATE `" + prefix + "chan` SET currentusers=currentusers-1 " "WHERE channel=channel_;" "END"; diff --git a/src/servers.cpp b/src/servers.cpp index 5f05c4d61..46e1a7077 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -32,6 +32,7 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano { syncing = true; juped = jupe; + quitting = false; Servers::ByName[sname] = this; if (!ssid.empty()) @@ -164,6 +165,7 @@ Server::~Server() void Server::Delete(const Anope::string &reason) { this->quit_reason = reason; + this->quitting = true; FOREACH_MOD(OnServerQuit, (this)); delete this; } @@ -315,6 +317,11 @@ bool Server::IsJuped() const return juped; } +bool Server::IsQuitting() const +{ + return quitting; +} + void Server::Notice(BotInfo *source, const Anope::string &message) { if (Config->UsePrivmsg && Config->DefPrivmsg) |