private MaskingTable GetTable(List <MaskingTable> lst)
        {
            lock (lst)
            {
                if (lst.Count > 0)
                {
                    MaskingTable rst = lst[0];

                    lst.RemoveAt(0);

                    return(rst);
                }
                else
                {
                    return(null);
                }
            }
        }
        private void MaskTable(MaskingTask task, MaskingTable table, out string reason)
        {
            reason = "取消操作";
            if (status.Stopped)
            {
                return;
            }

            if (Connect(task, task.Dest, out IDBMSReader source, task.Dest, out IDBMSWriter dest))
            {
                Dictionary <string, object> parms = new Dictionary <string, object>();

                dest.QueryParam(task.Params, parms);
                dest.BeginTransaction();
                try
                {
                    // 脱敏数据
                    MaskTableWithScript(task, table, parms, source, dest, out reason);
                    if (table.Status != DataStates.Error && !status.Stopped)
                    {
                        dest.CommitTransaction();
                        table.Status = DataStates.Done;
                    }
                    else
                    {
                        dest.RollbackTransaction();
                        table.Status = DataStates.Error;
                    }
                }
                catch (Exception ex)
                {
                    dest.RollbackTransaction();
                    table.Status = DataStates.Error;
                    reason       = ex.Message;
                }

                source.Close();
                dest.Close();
            }
        private void AnalyseTable(string file, MaskingTask task)
        {
            JObject             obj    = LoadAndDeserialize(file);
            JArray              tables = obj["tables"] as JArray;
            List <MaskingTable> buf    = new List <MaskingTable>();

            task.Params = obj["params"].ToString();

            // #1: 获取所有表
            for (int i = 0; i < tables.Count; i++)
            {
                JObject      o     = tables[i] as JObject;
                string       name  = o["name"].ToString();
                MaskingTable table = new MaskingTable()
                {
                    SourceName   = Table.AnalyseName(name),
                    SourceSchema = Table.AnalyseSchema(name),
                    DestName     = Table.AnalyseName(name),
                    DestSchema   = Table.AnalyseSchema(name),
                    Order        = int.Parse(o["order"].ToString()),
                    OrderSQL     = o["orderSQL"].ToString(),
                    WhereSQL     = o["whereSQL"].ToString(),
                    PageSize     = uint.Parse(o["pageSize"].ToString()),
                    WriteMode    = WriteModes.Append,
                    KeyFields    = o["keyFields"].ToString().Split(','),
                    SkipFields   = new string[] { },
                    MaskFields   = o["maskFields"].ToString().Split(','),
                    Filter       = o["filter"].ToString(),
                    KeepIdentity = false,
                    References   = new string[] { },
                    Total        = 0,
                    Progress     = 0,
                    Status       = DataStates.Idle
                };
                List <string> destFields = new List <string>();

                destFields.AddRange(table.KeyFields);
                destFields.AddRange(table.MaskFields);
                table.DestFields = destFields.ToArray();

                buf.Add(table);

                if (table.WriteMode == WriteModes.Update && "".Equals(table.KeyFields[0]))
                {
                    throw new Exception($"表 {table.SourceName} 配置有误!更新模式必须指定主键字段(keyFields)。");
                }
                if ("".Equals(table.OrderSQL))
                {
                    throw new Exception($"表 {table.SourceName} 配置有误!必须指定稳定的排序规则(orderSQL)。");
                }
                if (table.PageSize <= 0)
                {
                    throw new Exception($"表 {table.SourceName} 配置有误!批量记录数必须大于零(pageSize)。");
                }
                if (string.IsNullOrEmpty(table.Filter))
                {
                    throw new Exception($"表 {table.SourceName} 配置有误!必须指定过滤器(filter)。");
                }
            }

            task.Tables = buf.ToArray();
        }
        public void Execute(Instance ins, IStopStatus status)
        {
            this.status = status;

            foreach (Common.Task t in ins.Tasks)
            {
                if (status.Stopped)
                {
                    break;
                }

                if (t is MaskingTask task && task.Tables.Length > 0)
                {
                    task.StartTick = WinAPI.GetTickCount();
                    task.Status    = DataStates.Running;

                    // 构建待脱敏表清单
                    List <MaskingTable> lst      = new List <MaskingTable>();
                    TableComparer       comparer = new TableComparer();

                    foreach (Table tt in task.Tables)
                    {
                        if (tt is MaskingTable table)
                        {
                            lst.Add(table);
                        }
                    }
                    lst.Sort(comparer);

                    // 开始脱敏
                    try
                    {
                        Parallel.ForEach(CreateThreadAction((int)task.Threads), i =>
                        {
                            MaskingTable table = GetTable(lst);

                            while (table != null)
                            {
                                Logger.WriteLog($"{task.Dest.Server}/{task.Dest.DB}.{table.SourceName}", "脱敏开始...");

                                MaskTable(task, table, out string reason);
                                if (table.Status == DataStates.Done)
                                {
                                    Logger.WriteLog($"{task.Dest.Server}/{task.Dest.DB}.{table.SourceName}", "脱敏成功。");
                                    Logger.WriteRpt(task.Dest.Server, task.Dest.DB, table.SourceName, "成功",
                                                    table.Progress.ToString("#,##0"));
                                }
                                else
                                {
                                    task.Status    = DataStates.RunningError;
                                    task.ErrorMsg  = reason;
                                    task.Progress -= table.Progress;
                                    Logger.WriteLog($"{task.Dest.Server}/{task.Dest.DB}.{table.SourceName}",
                                                    $"脱敏失败!{reason}");
                                    Logger.WriteRpt(task.Dest.Server, task.Dest.DB, table.SourceName, "失败", reason);
                                }

                                table = GetTable(lst);
                            }
                        });

                        if (status.Stopped || task.Status == DataStates.RunningError || task.Status == DataStates.Error)
                        {
                            task.Status = DataStates.Error;
                            Logger.WriteLog($"{task.Dest.Server}/{task.Dest.DB}", "脱敏失败!");
                        }
                        else
                        {
                            task.Status = DataStates.Done;
                            Logger.WriteLog($"{task.Dest.Server}/{task.Dest.DB}", "脱敏成功!");
                        }
                    }
                    catch (Exception ex)
                    {
                        task.Status   = DataStates.Error;
                        task.ErrorMsg = ex.Message;
                        Logger.WriteLog($"{task.Dest.Server}/{task.Dest.DB}", $"脱敏失败!{ex.Message}");
                    }
                    task.StartTick = WinAPI.GetTickCount() - task.StartTick;
                }
            }
        }