Глобальный скрипт для удаления старых таблиц 2

Материал из BiTel WiKi

Перейти к: навигация, поиск

Глобальный скрипт для удаления старых таблиц (drop/truncate/dump)

Скрипт удаляет произвольные месячные или дневные таблицы в соответствии с настройками в глобальном конфиге биллинга:

#Скрипт удаления старых таблиц DropOldTables
script.droptables.debug=0
#уведомление на email со списком удалённых таблиц
script.droptables.email=admin@provider.ru
#храним бэкапы
script.droptables.dirbackup=/mnt/backup/
script.droptables.dumpstring=mysqldump -uroot -pbilling -P 3306 bgbilling

Удаляем (drop=1) или транкейтим (drop=0[default]) месячную таблицу старше 3 месяцев, при необходимости делаем дамп (backup=1):

script.droptables.month.1.prefix=log_server_12
script.droptables.month.1.months=3
script.droptables.month.1.drop=0
script.droptables.month.1.backup=0

Удаляем (drop=1) или транкейтим (drop=0[default]) дневную таблицу старше 3 месяцев, при необходимости делаем дамп (backup=1):

script.droptables.day.1.prefix=data_log_18
script.droptables.day.1.months=3
script.droptables.day.1.drop=1
script.droptables.day.1.backup=0

Делаем optimize table за 2 месяца, начиная с предыдущего:

script.droptables.optimize.month.1.prefix=log_session_18
script.droptables.optimize.month.1.months=2

Удаляем записи из session_detail модуля dialup, но только если по ним нет начислений в session_account (удаляем бесплатные трафики). Затем делаем Optimize table. В примере удаляются данные за 1 месяц старше 3 лет:

script.droptables.dialup.cleanup.1.mid=21
script.droptables.dialup.cleanup.1.months=37
script.droptables.dialup.cleanup.1.depth=1
package ru.dsi.bgbilling.kernel.scripts.global;
 
import bitel.billing.server.util.MailMsg;
import ru.bitel.bgbilling.kernel.script.server.dev.GlobalScriptBase;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.sql.ConnectionSet;
 
import java.io.IOException;
import java.sql.*;
import java.util.Calendar;
import java.util.Map;
 
import static ru.bitel.common.TimeUtils.*;
/**
 * Чистим старые таблицы
 */
public class DropOldTables
        extends GlobalScriptBase
{
    @Override
    public void execute( Setup setup, ConnectionSet connectionSet )
            throws Exception
    {
        ParameterMap params = setup.sub("script.droptables.");
        String prefix;
        String name;
        int months;
        int flagDrop = 0;
        int backup = 0;
        Calendar cal;
        StringBuilder report = new StringBuilder();
        boolean debug = params.getBoolean("debug", false);
        String email = params.get("email", null);
        String backupdir=params.get("dirbackup",null);
        String dumpstring=params.get("dumpstring",null);
 
        //daily
        //Подневные таблицы вида prefix_yyyymmdd
        // например, удаляем cdr-логи телефонии старше 6 месяцев (оставляем текущий + 5 предыдущих):
        //script.droptables.day.1.prefix=data_log_18
        //script.droptables.day.1.months=6
        for(Map.Entry<Integer, ParameterMap> entry: params.subIndexed("day.").entrySet()){
            prefix = entry.getValue().get("prefix");
            months = entry.getValue().getInt("months", 0);
            flagDrop = entry.getValue().getInt("drop", 0);
            backup = entry.getValue().getInt("backup", 0);
            if(prefix==null || months<=0){
                error("'prefix' not found or 'months'<=0 for config params script.droptables.day."+entry.getKey()+".");
                continue;
            }
            cal = Calendar.getInstance();
            cal.add(Calendar.MONTH,-months);
            //Удаляем 12 месяцев начиная с now.mm-months
            for(int i=1;i<=12;i++) {
                for (int dd=1; dd<=cal.getActualMaximum(Calendar.DAY_OF_MONTH); dd++){
                    cal.set(Calendar.DAY_OF_MONTH, dd);
                    name = prefix + format(cal, "_yyyyMMdd");
                    deleteRecord(connectionSet, name, flagDrop, report, backupdir, dumpstring, backup, debug);
                }
                cal.add(Calendar.MONTH,-1);
            }
        }
 
        //monthly
        //Помесячные таблицы вида prefix_yyyymm
        // например, удаляем radius-логи телефонии/dialup старше 6 месяцев (оставляем текущий + 5 предыдущих):
        //script.droptables.month.1.prefix=log_server_12
        //script.droptables.month.1.months=6
        for(Map.Entry<Integer, ParameterMap> entry: params.subIndexed("month.").entrySet()){
            prefix = entry.getValue().get("prefix");
            months = entry.getValue().getInt("months", 0);
            flagDrop = entry.getValue().getInt("drop", 0);
            backup = entry.getValue().getInt("backup", 0);
            if(prefix==null || months<=0){
                error("'prefix' not found or 'months'<=0 for config params script.droptables.month."+entry.getKey()+".");
                continue;
            }
            cal = Calendar.getInstance();
            cal.add(Calendar.MONTH,-months);
            //Удаляем 12 месяцев начиная с now.mm-months
            for(int i=1;i<=12;i++) {
                name = prefix + format(cal, "_yyyyMM");
                deleteRecord(connectionSet, name,flagDrop,report, backupdir, dumpstring, backup, debug);
                cal.add(Calendar.MONTH,-1);
            }
        }
 
        PreparedStatement ps;
 
        //monthly - optimize tables
        //Помесячные таблицы вида prefix_yyyymm
        // например, оптимизируем логи телефонии/dialup за 6 месяцев, начиная с предыдущего:
        //script.droptables.optimize.month.1.prefix=log_session_18
        //script.droptables.optimize.month.1.months=6
        for(Map.Entry<Integer, ParameterMap> entry: params.subIndexed("optimize.month.").entrySet()){
            prefix = entry.getValue().get("prefix");
            months = entry.getValue().getInt("months", 0);
            if(prefix==null || months<=0){
                error("'prefix' not found or 'months'<=0 for config params script.droptables.optimize.month."+entry.getKey()+".");
                continue;
            }
            cal = Calendar.getInstance();
            cal.add(Calendar.MONTH,-1);
            //Optimize 12 месяцев начиная с now.mm-months
            for(int i=1;i<=months;i++) {
                name = prefix + format(cal, "_yyyyMM");
                if(tableExists(connectionSet.getConnection(), name)) {
                    ps = connectionSet.getConnection().prepareStatement("optimize table "+name);
                    ps.executeUpdate();
                    ps.close();
                    print("OPTIMIZE TABLE "+name);
                    report.append("OPTIMIZE TABLE ").append(name).append("\n");
                }
                cal.add(Calendar.MONTH,-1);
            }
        }
 
        //monthly - удаляем бесплатные трафики из session_detail_mid_yyyymm модуля dialup
        //например, чистим трафики в таблицах старше 3 лет глубиной в 1 месяц и сразу делаем optimize
        //script.droptables.dialup.cleanup.1.mid=21
        //script.droptables.dialup.cleanup.1.months=36
        //script.droptables.dialup.cleanup.1.depth=1
        //script.droptables.dialup.cleanup.1.optimize=1
        int mid;
        int depth;
        int optimize;
        for(Map.Entry<Integer, ParameterMap> entry: params.subIndexed("dialup.cleanup.").entrySet()){
            mid = entry.getValue().getInt("mid",0 );
            months = entry.getValue().getInt("months", 0);
            depth = entry.getValue().getInt("depth", 1);
            optimize = entry.getValue().getInt("optimize", 1);
            if(mid<=0 || months<=0){
                error("'mid' or 'months'<=0 for config params script.droptables.dialup.cleanup."+entry.getKey()+".");
                continue;
            }
            cal = Calendar.getInstance();
            cal.add(Calendar.MONTH,-months);
            //Optimize depth месяцев начиная с now.mm-months
            int max_cid;
            int min_cid;
            int row_count;
            int counter;
            ResultSet rs;
            for(int i=1;i<=depth;i++) {
                name = "session_detail_"+mid + format(cal, "_yyyyMM");
                if(tableExists(connectionSet.getConnection(), name)) {
                    //Будем делать delete кусочками. limit в mysql нельзя использовать в delete с join.
                    //Поэтому удаляем с отсечкой по индексному полю cid с градацией в 1000 cid-ов
                    ps = connectionSet.getConnection().prepareStatement("select max(cid) from "+name);
                    rs = ps.executeQuery();
                    max_cid = 0;
                    if(rs.next()){
                        max_cid = rs.getInt(1);
                    }
                    rs.close();
                    ps.close();
 
                    ps = connectionSet.getConnection().prepareStatement("select min(cid) from "+name);
                    rs = ps.executeQuery();
                    min_cid = 0;
                    if(rs.next()){
                        min_cid = rs.getInt(1);
                    }
                    rs.close();
                    ps.close();
 
                    row_count=0;
                    counter=0;
                    for(int id=max_cid-1000; id>min_cid-1000;id-=1000) {
                        ps = connectionSet.getConnection().prepareStatement("delete d from " + name + " d " +
                                "left join session_account_" + mid + format(cal, "_yyyyMM") + " a on d.session_id=a.session_id and d.sid=a.sid " +
                                "where a.session_id is null and d.cid>="+id);
                        row_count+=ps.executeUpdate();
                        counter++;
                        ps.close();
                    }
                    print("* delete ~~~ from TABLE " + name+" ["+row_count+" rows, "+counter+" iterations]");
                    report.append("* delete ~~~ from TABLE ").append(name).append("\n");
 
                    if(optimize==1) {
                        ps = connectionSet.getConnection().prepareStatement("optimize table " + name);
                        ps.executeUpdate();
                        ps.close();
                        print("OPTIMIZE TABLE " + name);
                        report.append("OPTIMIZE TABLE ").append(name).append("\n");
                    }
                }
                cal.add(Calendar.MONTH,-1);
            }
        }
 
        if(email!=null && !"".equals(email)){
            MailMsg msg = new MailMsg(setup);
            msg.sendMessage(email, "Удаление старых таблиц", report.toString());
        }
    }
    private void deleteRecord(ConnectionSet connectionSet, String tableName, int flagDrop, StringBuilder report, String backupdir, String dumpstring, int backup, boolean debug){
        if(tableExists(connectionSet.getConnection(), tableName)) {
            String trorDrop=flagDrop==0?"TRUNCATE":"DROP TABLE";
            String filedm=backupdir+"/"+tableName;
 
 
            print(trorDrop+" " + tableName);
            if (!debug){
                int exitValue=1;
                if(backup==1){
                    Runtime rt = Runtime.getRuntime();
                    String commandDump = dumpstring+" "+tableName+" -r "+ filedm+".sql";
                    String commandZip = " zip "+filedm+".zip "+filedm+".sql";
                    String commandRm = "rm "+filedm+".sql";
                    try {
                        Process proc=rt.exec(commandDump);
                        proc.waitFor();
                        if (proc.exitValue()==0){
                            proc=rt.exec(commandZip);
                            proc.waitFor();
                            if(proc.exitValue()==0){
                                proc=rt.exec(commandRm);
                                proc.waitFor();
                            }
                        }
                        exitValue=proc.exitValue();
 
                    } catch (IOException e) {
                        error("Не удалось сделать бэкап таблицы " + tableName+"; Exeption : "+e.toString());
                    } catch (InterruptedException e) {
                        error("Не удалось сделать бэкап таблицы " + tableName+"; Exeption : "+e.toString());
                    }
                }
                if((backup==1&&exitValue==0)||(backup==0)){
                    try {
                        Statement st = connectionSet.getConnection().createStatement();
                        st.executeUpdate(trorDrop+" " + tableName);
                        st.close();
                    }catch (SQLException e){
                        error(e.getMessage());
                    }
                }
 
            }
            report.append(trorDrop).append(" ").append(tableName).append("\n");
        }
    }
    private boolean tableExists(Connection con, String tableName){
        boolean result=false;
        try {
            PreparedStatement ps = con.prepareStatement("SHOW TABLES LIKE ?");
            ps.setString(1, tableName);
            ResultSet rs = ps.executeQuery();
            result = rs.next();
            rs.close();
            ps.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
 
}

Пример конфига скрипта:

#Скрипт удаления старых таблиц DropOldTables
script.droptables.debug=0
#уведомление на email со списком удалённых таблиц
script.droptables.email=admin@provider.ru
#храним бэкапы
script.droptables.dirbackup=/mnt/backup/bgtables
script.droptables.dumpstring=mysqldump -uroot -p12345 -P 3306 -h 127.0.0.1 bgbilling
script.droptables.month.1.prefix=log_server_1
script.droptables.month.1.months=6
script.droptables.month.2.prefix=log_error_1
script.droptables.month.2.months=6
script.droptables.month.3.prefix=log_function_process
script.droptables.month.3.months=6
script.droptables.month.4.prefix=connection_log_entry_28
script.droptables.month.4.months=6
script.droptables.month.5.prefix=inet_auth_error_28
script.droptables.month.5.months=6
script.droptables.month.6.prefix=log_gscript_process
script.droptables.month.6.months=6
script.droptables.month.6.drop=1
script.droptables.month.7.prefix=npay_add_cost_detail_16
script.droptables.month.7.months=6
script.droptables.month.7.drop=1
script.droptables.month.8.prefix=npay_detail_16
script.droptables.month.8.months=24
script.droptables.month.8.drop=1
script.droptables.month.9.prefix=source_data
script.droptables.month.9.months=9
script.droptables.month.9.drop=1
script.droptables.month.10.prefix=tariff_detail_1
script.droptables.month.10.months=6
script.droptables.month.10.drop=1
script.droptables.month.11.prefix=bgs_query_log
script.droptables.month.11.months=12
script.droptables.month.11.drop=1
script.droptables.month.11.backup=1
script.droptables.month.12.prefix=web_query_log
script.droptables.month.12.months=6
script.droptables.month.12.drop=1
script.droptables.month.12.backup=1
script.droptables.day.1.prefix=data_log_18
script.droptables.day.1.months=3
script.droptables.day.1.drop=1
script.droptables.optimize.month.1.prefix=log_session_18
script.droptables.optimize.month.1.months=2
script.droptables.optimize.month.2.prefix=log_session_29
script.droptables.optimize.month.2.months=2
script.droptables.dialup.cleanup.1.mid=21
script.droptables.dialup.cleanup.1.months=37
script.droptables.dialup.cleanup.1.depth=1
#

--Cromeshnic 07:40, 1 августа 2018 (UTC)

Личные инструменты