Пример #1
0
        // 清除长期不活动的 Person 对象,顺便写入统计信息
        // 尽早写入统计信息,可以减少意外 Down 掉的丢失写入的损害
        public void CleanPersons(TimeSpan delta,
                                 Statis statis)
        {
            // List<string> remove_keys = new List<string>();

            List <Person> remove_persons = new List <Person>(); // 需要清除的对象
            List <Person> flush_persons  = new List <Person>(); // 需要写入统计数据的对象

            // 读锁定并不阻碍一般性访问
            if (this.m_lock.TryEnterReadLock(m_nLockTimeout) == false)
            {
                throw new ApplicationException("锁定尝试中超时");
            }
            try
            {
                foreach (string key in this.Keys)
                {
                    Person person = (Person)this[key];

                    if (person == null)
                    {
                        continue;
                    }

                    if ((DateTime.Now - person.LastUsedTime) >= delta)
                    {
                        // remove_keys.Add(key);   // 这里不能删除,因为 foreach 还要用枚举器
                        remove_persons.Add(person);
                    }
                    else if (person.StatisWrited == false)
                    {
                        flush_persons.Add(person);
                    }
                }
            }
            finally
            {
                this.m_lock.ExitReadLock();
            }

#if NO
            if (remove_keys.Count == 0)
            {
                return;
            }
#endif
            // 移走过期的对象
            if (remove_persons.Count > 0)
            {
                // 因为要删除某些元素,所以用写锁定
                List <Person> delete_persons = new List <Person>();
                if (this.m_lock.TryEnterWriteLock(m_nLockTimeout) == false)
                {
                    throw new ApplicationException("锁定尝试中超时");
                }
                try
                {
#if NO
                    foreach (string key in remove_keys)
                    {
                        Person person = (Person)this[key];
                        if (person == null)
                        {
                            continue;   // sessionid 没有找到对应的 Session 对象
                        }
                        // 和 id 的 hashtable 脱离关系
                        this.Remove(key);

                        delete_persons.Add(person);
                    }
#endif
                    foreach (Person person in remove_persons)
                    {
                        this.Remove(person.ID);
                    }
                }
                finally
                {
                    this.m_lock.ExitWriteLock();
                }
            }

            // 写入统计信息
            if (statis != null)
            {
                foreach (Person person in remove_persons)
                {
                    // TODO: 可以按照馆代码统计聚类后,减少写入 Statis 的次数
                    if (person.StatisWrited == false)
                    {
                        // 增量统计数
                        statis.IncreaseEntryValue(
                            person.LibraryCode,
                            "出纳",
                            "读者数",
                            1);
                        person.StatisWrited = true;
                        // person.Close();
                    }
                }

                foreach (Person person in flush_persons)
                {
                    if (person.StatisWrited == false)
                    {
                        // 增量统计数
                        statis.IncreaseEntryValue(
                            person.LibraryCode,
                            "出纳",
                            "读者数",
                            1);
                        person.StatisWrited = true;
                        // person.Close();
                    }
                }
            }
        }
Пример #2
0
        public int LoadCfg(
            bool bReload,
            string strDataDir,
            string strHostDir,  // 为了脚本编译时候获得dll目录
            out string strError)
        {
            strError = "";
            int nRet = 0;
            LibraryApplication app = this;  // new CirculationApplication();

            // this.m_lock.AcquireWriterLock(m_nLockTimeout);
            this.LockForWrite();    // 2016/10/16
            try
            {

                // 装载配置文件的过程,只能消除以前的 StartError 挂起状态,其他状态是无法消除的
                // 本函数过程也约定好,只进行 StartError 挂起,不做其他挂起
#if NO
            if (app.HangupReason == LibraryServer.HangupReason.StartingError)
                app.HangupReason = LibraryServer.HangupReason.None;
#endif
                if (app.HangupList.Count > 0)
                {
                    ClearHangup("StartingError");
                }
                try
                {
                    DateTime start = DateTime.Now;

                    this.DataDir = strDataDir;
                    this.HostDir = strHostDir;

                    string strFileName = PathUtil.MergePath(strDataDir, "library.xml");
                    string strBinDir = strHostDir;  //  PathUtil.MergePath(strHostDir, "bin");
                    string strCfgDir = PathUtil.MergePath(strDataDir, "cfgs");
                    string strCfgMapDir = PathUtil.MergePath(strDataDir, "cfgsmap");
                    string strLogDir = PathUtil.MergePath(strDataDir, "log");
                    string strOperLogDir = PathUtil.MergePath(strDataDir, "operlog");
                    string strZhengyuanDir = PathUtil.MergePath(strDataDir, "zhengyuan");
                    string strDkywDir = PathUtil.MergePath(strDataDir, "dkyw");
                    string strPatronReplicationDir = PathUtil.MergePath(strDataDir, "patronreplication");
                    string strStatisDir = PathUtil.MergePath(strDataDir, "statis");
                    string strSessionDir = PathUtil.MergePath(strDataDir, "session");
                    string strColumnDir = PathUtil.MergePath(strDataDir, "column");
                    string strTempDir = PathUtil.MergePath(strDataDir, "temp");

                    app.m_strFileName = strFileName;

                    app.CfgDir = strCfgDir;

                    app.CfgMapDir = strCfgMapDir;
                    PathUtil.CreateDirIfNeed(app.CfgMapDir);	// 确保目录创建


                    // log
                    app.LogDir = strLogDir;	// 日志存储目录
                    PathUtil.CreateDirIfNeed(app.LogDir);	// 确保目录创建

                    // zhengyuan 一卡通
                    app.ZhengyuanDir = strZhengyuanDir;
                    PathUtil.CreateDirIfNeed(app.ZhengyuanDir);	// 确保目录创建

                    // dkyw 一卡通
                    app.DkywDir = strDkywDir;
                    PathUtil.CreateDirIfNeed(app.DkywDir);	// 确保目录创建

                    // patron replication
                    app.PatronReplicationDir = strPatronReplicationDir;
                    PathUtil.CreateDirIfNeed(app.PatronReplicationDir);	// 确保目录创建


                    // statis 统计文件
                    app.StatisDir = strStatisDir;
                    PathUtil.CreateDirIfNeed(app.StatisDir);	// 确保目录创建

                    // session临时文件
                    app.SessionDir = strSessionDir;
                    PathUtil.CreateDirIfNeed(app.SessionDir);	// 确保目录创建

                    if (bReload == false)
                        CleanSessionDir(this.SessionDir);

                    // 各种临时文件
                    app.TempDir = strTempDir;
                    PathUtil.CreateDirIfNeed(app.TempDir);	// 确保目录创建

                    if (bReload == false)
                    {
#if NO
                    try
                    {
                        string strTempFileName = Path.GetTempFileName();
                        File.Delete(strTempFileName);
                        string strTempDir1 = Path.GetDirectoryName(strTempFileName);
                        long count = 0;
                        long size = PathUtil.GetAllFileSize(strTempDir1, ref count);
                        app.WriteErrorLog("系统临时文件目录 " + Path.GetTempPath() + " 内的全部临时文件尺寸为 " + size.ToString() + ", 文件个数为 " + count.ToString());
                    }
                    catch
                    {
                    }
#endif

#if NO
                    if (PathUtil.TryClearDir(app.TempDir) == false)
                        app.WriteErrorLog("清除临时文件目录 " + app.TempDir + " 时出错");
#endif
                        try
                        {
                            PathUtil.ClearDir(app.TempDir);
                        }
                        catch (Exception ex)
                        {
                            app.WriteErrorLog("清除临时文件目录 " + app.TempDir + " 时出现异常: " + ExceptionUtil.GetDebugText(ex));
                        }
                    }

                    this.InitialLoginCache();
                    this.InitialBiblioSummaryCache();

                    if (bReload == false)
                    {
                        if (app.HasAppBeenKilled() == true)
                        {
                            app.WriteErrorLog("*** 发现library application先前曾被意外终止 ***");
                        }
                    }

                    this.WriteErrorLog("*********");

                    if (bReload == true)
                        app.WriteErrorLog("library (" + Version + ") application 开始重新装载 " + this.m_strFileName);
                    else
                        app.WriteErrorLog("library (" + Version + ") application 开始初始化。");

                    //
#if NO
            if (bReload == false)
            {
                app.m_strWebuiFileName = PathUtil.MergePath(strDataDir, "webui.xml");
                // string strWebUiFileName = PathUtil.MergePath(strDataDir, "webui.xml");
                nRet = LoadWebuiCfgDom(out strError);
                if (nRet == -1)
                {
                    // strError = "装载配置文件-- '" + strWebUiFileName + "'时发生错误,原因:" + ex.Message;
                    app.WriteErrorLog(strError);
                    goto ERROR1;
                }
            }
#endif

#if LOG_INFO
                    app.WriteErrorLog("INFO: 开始装载 " + strFileName + " 到 XMLDOM");
#endif

                    //

                    XmlDocument dom = new XmlDocument();
                    try
                    {
                        dom.Load(strFileName);
                    }
                    catch (FileNotFoundException)
                    {
                        strError = "file '" + strFileName + "' not found ...";
                        goto ERROR1;
                    }
                    catch (Exception ex)
                    {
                        strError = "装载配置文件-- '" + strFileName + "' 时发生错误,错误类型:" + ex.GetType().ToString() + ",原因:" + ex.Message;
                        app.WriteErrorLog(strError);
                        // throw ex;
                        goto ERROR1;
                    }

                    app.LibraryCfgDom = dom;

#if LOG_INFO
                    app.WriteErrorLog("INFO: 初始化内存参数");
#endif

                    // *** 进入内存的参数开始
                    // 注意修改了这些参数的结构后,必须相应修改Save()函数的相关片断

                    // 2011/1/7
                    bool bValue = false;
                    DomUtil.GetBooleanParam(app.LibraryCfgDom.DocumentElement,
                        "debugMode",
                        false,
                        out bValue,
                        out strError);
                    this.DebugMode = bValue;
                    WriteErrorLog("是否为调试态: " + this.DebugMode);

                    // 2013/4/10 
                    // uid
                    this.UID = app.LibraryCfgDom.DocumentElement.GetAttribute("uid");
                    if (string.IsNullOrEmpty(this.UID) == true)
                    {
                        this.UID = Guid.NewGuid().ToString();
                        this.Changed = true;
                        WriteErrorLog("自动为 library.xml 添加 uid '" + this.UID + "'");
                    }

                    // 内核参数
                    // 元素<rmsserver>
                    // 属性url/username/password
                    XmlElement node = dom.DocumentElement.SelectSingleNode("rmsserver") as XmlElement;
                    if (node != null)
                    {
                        app.WsUrl = DomUtil.GetAttr(node, "url");

                        if (app.WsUrl.IndexOf(".asmx") != -1)
                        {
                            strError = "装载配置文件 '" + strFileName + "' 过程中发生错误: <rmsserver>元素url属性中的 dp2内核 服务器URL '" + app.WsUrl + "' 不正确,应当为非.asmx形态的地址...";
                            app.WriteErrorLog(strError);
                            goto ERROR1;
                        }

                        app.ManagerUserName = DomUtil.GetAttr(node,
                            "username");

                        try
                        {
                            app.ManagerPassword = Cryptography.Decrypt(
                                DomUtil.GetAttr(node, "password"),
                                EncryptKey);
                        }
                        catch
                        {
                            strError = "<rmsserver>元素password属性中的密码设置不正确";
                            // throw new Exception();
                            goto ERROR1;
                        }

                        CfgsMap = new CfgsMap(this.CfgMapDir/*,
                        this.WsUrl*/);
                        CfgsMap.Clear();
                    }
                    else
                    {
                        app.WsUrl = "";
                        app.ManagerUserName = "";
                        app.ManagerPassword = "";
                    }

                    // 元素 <mongoDB>
                    // 属性 connectionString / instancePrefix
                    node = dom.DocumentElement.SelectSingleNode("mongoDB") as XmlElement;
                    if (node != null)
                    {
                        this.MongoDbConnStr = DomUtil.GetAttr(node, "connectionString");
                        this.MongoDbInstancePrefix = node.GetAttribute("instancePrefix");
                    }
                    else
                    {
                        this.MongoDbConnStr = "";
                        this.MongoDbInstancePrefix = "";
                        this.AccessLogDatabase = new AccessLogDatabase();
                        this.HitCountDatabase = new HitCountDatabase();
                        this.ChargingOperDatabase = new ChargingOperDatabase();
                    }

                    // 预约到书
                    // 元素<arrived>
                    // 属性dbname/reserveTimeSpan/outofReservationThreshold/canReserveOnshelf/notifyTypes
                    node = dom.DocumentElement.SelectSingleNode("arrived") as XmlElement;
                    if (node != null)
                    {
                        app.ArrivedDbName = DomUtil.GetAttr(node, "dbname");
                        app.ArrivedReserveTimeSpan = DomUtil.GetAttr(node, "reserveTimeSpan");

                        int nValue = 0;
                        nRet = DomUtil.GetIntegerParam(node,
                            "outofReservationThreshold",
                            10,
                            out nValue,
                            out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog("元素<arrived>属性outofReservationThreshold读入时发生错误: " + strError);
                            goto ERROR1;
                        }

                        app.OutofReservationThreshold = nValue;

                        bValue = false;
                        nRet = DomUtil.GetBooleanParam(node,
                            "canReserveOnshelf",
                            true,
                            out bValue,
                            out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog("元素<arrived>属性canReserveOnshelf读入时发生错误: " + strError);
                            goto ERROR1;
                        }

                        app.CanReserveOnshelf = bValue;

                        // 没有这个属性的时候,默认 "dpmail,email",否则依其值,哪怕为 ""
                        if (node.GetAttributeNode("notifyTypes") == null)
                            app.ArrivedNotifyTypes = "dpmail,email";
                        else
                            app.ArrivedNotifyTypes = node.GetAttribute("notifyTypes");

                    }
                    else
                    {
                        app.ArrivedDbName = "";
                        app.ArrivedReserveTimeSpan = "";
                        app.OutofReservationThreshold = 10;
                        app.CanReserveOnshelf = true;
                        app.ArrivedNotifyTypes = "dpmail,email";
                    }

                    // 2013/9/24
                    // 借期提醒通知定义
                    // 元素 <monitors/readersMonitor>
                    // 属性 notifyDef
                    node = dom.DocumentElement.SelectSingleNode("monitors/readersMonitor") as XmlElement;
                    if (node != null)
                    {
                        // 提醒通知的定义
                        app.NotifyDef = DomUtil.GetAttr(node, "notifyDef");
                    }
                    else
                    {
                        app.NotifyDef = "";
                    }

                    // <login>
                    node = dom.DocumentElement.SelectSingleNode("login") as XmlElement;
                    if (node != null)
                    {
                        this.CheckClientVersion = DomUtil.GetBooleanParam(node,
                            "checkClientVersion",
                            false);
                    }
                    else
                    {
                        this.CheckClientVersion = false;
                    }

                    // <circulation>
                    node = dom.DocumentElement.SelectSingleNode("circulation") as XmlElement;
                    if (node != null)
                    {
                        {
                            string strList = DomUtil.GetAttr(node, "patronAdditionalFroms");
                            if (string.IsNullOrEmpty(strList) == false)
                                this.PatronAdditionalFroms = StringUtil.SplitList(strList);
                            else
                                this.PatronAdditionalFroms = new List<string>();
                        }

                        {
                            string strList = DomUtil.GetAttr(node, "patronAdditionalFields");
                            if (string.IsNullOrEmpty(strList) == false)
                                this.PatronAdditionalFields = StringUtil.SplitList(strList);
                            else
                                this.PatronAdditionalFields = new List<string>();
                        }

                        {
                            string strList = DomUtil.GetAttr(node, "patronReplicationFields");
                            if (string.IsNullOrEmpty(strList) == false)
                                this.PatronReplicationFields = StringUtil.SplitList(strList);
                            else
                                this.PatronReplicationFields = StringUtil.SplitList(strList);
                        }

                        int v = 0;
                        nRet = DomUtil.GetIntegerParam(node,
                            "maxPatronHistoryItems",
                            10, // 100,
                            out v,
                            out strError);
                        if (nRet == -1)
                            app.WriteErrorLog(strError);
                        this.MaxPatronHistoryItems = v;

                        nRet = DomUtil.GetIntegerParam(node,
        "maxItemHistoryItems",
        10, // 100,
        out v,
        out strError);
                        if (nRet == -1)
                            app.WriteErrorLog(strError);
                        this.MaxItemHistoryItems = v;

                        this.VerifyBarcode = DomUtil.GetBooleanParam(node, "verifyBarcode", false);

                        this.AcceptBlankItemBarcode = DomUtil.GetBooleanParam(node, "acceptBlankItemBarcode", true);

                        this.AcceptBlankReaderBarcode = DomUtil.GetBooleanParam(node, "acceptBlankReaderBarcode", true);

                        this.VerifyBookType = DomUtil.GetBooleanParam(node, "verifyBookType", false);
                        this.VerifyReaderType = DomUtil.GetBooleanParam(node, "verifyReaderType", false);
                        this.BorrowCheckOverdue = DomUtil.GetBooleanParam(node, "borrowCheckOverdue", true);

                        this.CirculationNotifyTypes = node.GetAttribute("notifyTypes");
                    }
                    else
                    {
                        this.PatronAdditionalFroms = new List<string>();
                        this.PatronAdditionalFields = new List<string>();
                        this.MaxPatronHistoryItems = DEFAULT_MAXPATRONHITSTORYITEMS;
                        this.MaxItemHistoryItems = DEFAULT_MAXITEMHISTORYITEMS;
                        this.VerifyBarcode = false;
                        this.AcceptBlankItemBarcode = true;
                        this.AcceptBlankReaderBarcode = true;
                        this.VerifyBookType = false;
                        this.VerifyReaderType = false;
                        this.BorrowCheckOverdue = true;
                        this.CirculationNotifyTypes = "";
                    }

                    // <channel>
                    node = dom.DocumentElement.SelectSingleNode("channel") as XmlElement;
                    if (node != null)
                    {
                        int v = 0;
                        nRet = DomUtil.GetIntegerParam(node,
                            "maxChannelsPerIP",
                            50,
                            out v,
                            out strError);
                        if (nRet == -1)
                            app.WriteErrorLog(strError);
                        if (this.SessionTable != null)
                            this.SessionTable.MaxSessionsPerIp = v;

                        nRet = DomUtil.GetIntegerParam(node,
        "maxChannelsLocalhost",
        150,
        out v,
        out strError);
                        if (nRet == -1)
                            app.WriteErrorLog(strError);
                        if (this.SessionTable != null)
                            this.SessionTable.MaxSessionsLocalHost = v;
                    }
                    else
                    {
                        if (this.SessionTable != null)
                        {
                            this.SessionTable.MaxSessionsPerIp = 50;
                            this.SessionTable.MaxSessionsLocalHost = 150;
                        }
                    }

                    // <cataloging>
                    node = dom.DocumentElement.SelectSingleNode("cataloging") as XmlElement;
                    if (node != null)
                    {
                        // 是否允许删除带有下级记录的书目记录
                        bValue = true;
                        nRet = DomUtil.GetBooleanParam(node,
                            "deleteBiblioSubRecords",
                            true,
                            out bValue,
                            out strError);
                        if (nRet == -1)
                            app.WriteErrorLog(strError);
                        this.DeleteBiblioSubRecords = bValue;
                    }
                    else
                    {
                        this.DeleteBiblioSubRecords = true;
                    }

                    // 入馆登记
                    // 元素<passgate>
                    // 属性writeOperLog
                    node = dom.DocumentElement.SelectSingleNode("passgate") as XmlElement;
                    if (node != null)
                    {
                        string strWriteOperLog = DomUtil.GetAttr(node, "writeOperLog");

                        this.PassgateWriteToOperLog = ToBoolean(strWriteOperLog,
                            true);
                    }
                    else
                    {
                        this.PassgateWriteToOperLog = true;
                    }

                    // 对象管理
                    // 元素<object>
                    // 属性 writeOperLog
                    node = dom.DocumentElement.SelectSingleNode("object") as XmlElement;
                    if (node != null)
                    {
                        string strWriteOperLog = DomUtil.GetAttr(node, "writeGetResOperLog");

                        this.GetObjectWriteToOperLog = ToBoolean(strWriteOperLog,
                            false);
                    }
                    else
                    {
                        this.GetObjectWriteToOperLog = false;
                    }

                    // 2015/11/26
                    // 日志特性
                    // 元素<log>
                    node = dom.DocumentElement.SelectSingleNode("log") as XmlElement;
                    if (node != null)
                    {
                        int nValue = 0;
                        DomUtil.GetIntegerParam(node,
                            "accessLogMaxCountPerDay",
                            10000,
                            out nValue,
                            out strError);
                        this.AccessLogMaxCountPerDay = nValue;
                    }
                    else
                    {
                        this.AccessLogMaxCountPerDay = 10000;
                    }

                    // 消息
                    // 元素<message>
                    // 属性dbname/reserveTimeSpan/defaultQueue
                    node = dom.DocumentElement.SelectSingleNode("message") as XmlElement;
                    if (node != null)
                    {
                        this.MessageDbName = DomUtil.GetAttr(node, "dbname");
                        this.MessageReserveTimeSpan = DomUtil.GetAttr(node, "reserveTimeSpan");
                        // 2016/4/10
                        this.OutgoingQueue = DomUtil.GetAttr(node, "defaultQueue");

                        // 2010/12/31 add
                        if (String.IsNullOrEmpty(this.MessageReserveTimeSpan) == true)
                            this.MessageReserveTimeSpan = "365day";
                    }
                    else
                    {
                        this.MessageDbName = "";
                        this.MessageReserveTimeSpan = "365day";
                        this.OutgoingQueue = "";
                    }

                    // OPAC服务器
                    // 元素<opacServer>
                    // 属性url
                    node = dom.DocumentElement.SelectSingleNode("opacServer") as XmlElement;
                    if (node != null)
                    {
                        app.OpacServerUrl = DomUtil.GetAttr(node, "url");
                    }
                    else
                    {
                        app.OpacServerUrl = "";
                    }

                    // 违约金
                    // 元素<amerce>
                    // 属性dbname/overdueStyle
                    node = dom.DocumentElement.SelectSingleNode("amerce") as XmlElement;
                    if (node != null)
                    {
                        app.AmerceDbName = DomUtil.GetAttr(node, "dbname");
                        app.OverdueStyle = DomUtil.GetAttr(node, "overdueStyle");
                    }
                    else
                    {
                        app.AmerceDbName = "";
                        app.OverdueStyle = "";
                    }

                    // 发票
                    // 元素<invoice>
                    // 属性dbname
                    node = dom.DocumentElement.SelectSingleNode("invoice") as XmlElement;
                    if (node != null)
                    {
                        app.InvoiceDbName = DomUtil.GetAttr(node, "dbname");
                    }
                    else
                    {
                        app.InvoiceDbName = "";
                    }

                    // *** 进入内存的参数结束

                    // bin dir
                    app.BinDir = strBinDir;

                    nRet = 0;

                    {
#if LOG_INFO
                        app.WriteErrorLog("INFO: LoadReaderDbGroupParam");
#endif
                        // <readerdbgroup>
                        app.LoadReaderDbGroupParam(dom);

#if LOG_INFO
                        app.WriteErrorLog("INFO: LoadItemDbGroupParam");
#endif

                        // <itemdbgroup> 
                        nRet = app.LoadItemDbGroupParam(dom,
                            out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog(strError);
                            goto ERROR1;
                        }

                        // 临时的SessionInfo对象
                        SessionInfo session = new SessionInfo(this);
                        try
                        {
#if LOG_INFO
                            app.WriteErrorLog("INFO: InitialKdbs");
#endif

                            // 初始化kdbs
                            nRet = InitialKdbs(session.Channels,
                                out strError);
                            if (nRet == -1)
                            {
                                app.WriteErrorLog("ERR001 首次初始化kdbs失败: " + strError);
                                // DefaultThread可以重试初始化

                                // session.Close();
                                // goto ERROR1;
                            }
                            else
                            {
#if LOG_INFO
                                app.WriteErrorLog("INFO: CheckKernelVersion");
#endif

                                // 检查 dpKernel 版本号
                                nRet = CheckKernelVersion(session.Channels,
                                    out strError);
                                if (nRet == -1)
                                    goto ERROR1;
                            }

#if LOG_INFO
                            app.WriteErrorLog("INFO: InitialVdbs");
#endif

                            // 2008/6/6  重新初始化虚拟库定义
                            // 这样,其他地方调用的InitialVdbs()就可以去除了
                            // TODO: 为了提高运行速度,可以优化为,只有当<virtualDatabases>元素下的内容有改变时,才重新进行这个初始化
                            this.vdbs = null;
                            nRet = app.InitialVdbs(session.Channels,
                                out strError);
                            if (nRet == -1)
                            {
                                app.WriteErrorLog("ERR002 首次初始化vdbs失败: " + strError);
                            }

                        }
                        finally
                        {
                            session.CloseSession();
                            session = null;

#if LOG_INFO
                            app.WriteErrorLog("INFO: 临时 session 使用完毕");
#endif
                        }

                    }

                    // 时钟
                    string strClock = DomUtil.GetElementText(dom.DocumentElement, "clock");
                    try
                    {
                        this.Clock.Delta = Convert.ToInt64(strClock);
                    }
                    catch
                    {
                        // TODO: 写入错误日志
                    }

                    // *** 初始化操作日志环境
                    if (bReload == false)   // 2014/4/2
                    {
                        // this.OperLogDir = strOperLogDir;    // 2006/12/7 
#if LOG_INFO
                        app.WriteErrorLog("INFO: OperLog.Initial");
#endif

                        // oper log
                        nRet = this.OperLog.Initial(this,
                            strOperLogDir,
                            out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog(strError);
                            goto ERROR1;
                        }
                    }

                    // *** 初始化统计对象
                    // if (bReload == false)   // 2014/4/2
                    {
#if LOG_INFO
                        app.WriteErrorLog("INFO: Statis.Initial");
#endif

                        this.Statis = new Statis();
                        nRet = this.Statis.Initial(this, out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog(strError);
                            goto ERROR1;
                        }
                    }

#if LOG_INFO
                    app.WriteErrorLog("INFO: InitialLibraryHostAssembly");
#endif
                    // 初始化LibraryHostAssembly对象
                    // 必须在ReadersMonitor以前启动。否则其中用到脚本代码时会出错。2007/10/10 changed
                    // return:
                    //		-1	出错
                    //		0	成功
                    nRet = this.InitialLibraryHostAssembly(out strError);
                    if (nRet == -1)
                    {
                        app.WriteErrorLog(strError);
                        goto ERROR1;
                    }

#if LOG_INFO
                    app.WriteErrorLog("INFO: InitialExternalMessageInterfaces");
#endif

                    // 初始化扩展消息接口
                    nRet = app.InitialExternalMessageInterfaces(
                    out strError);
                    if (nRet == -1)
                    {
                        strError = "初始化扩展的消息接口时出错: " + strError;
                        app.WriteErrorLog(strError);
                        // goto ERROR1;
                    }

                    // 创建 MSMQ 消息队列
#if LOG_INFO
                    app.WriteErrorLog("INFO: Message Queue");
#endif

                    ///
                    app.InitialMsmq();

                    // 初始化 mongodb 相关对象
                    nRet = InitialMongoDatabases(out strError);
                    if (nRet == -1)
                    {
                        // app.HangupReason = LibraryServer.HangupReason.StartingError;
                        app.AddHangup("ERR002");
                        app.WriteErrorLog("ERR002 首次初始化 mongodb database 失败: " + strError);
                    }

#if LOG_INFO
                    app.WriteErrorLog("INFO: 准备下属数据库对象");
#endif
                    //
                    this.IssueItemDatabase = new IssueItemDatabase(this);
                    this.OrderItemDatabase = new OrderItemDatabase(this);
                    this.CommentItemDatabase = new CommentItemDatabase(this);

#if LOG_INFO
                    app.WriteErrorLog("INFO: MessageCenter");
#endif
                    // 
                    this.MessageCenter = new MessageCenter();
                    this.MessageCenter.ServerUrl = this.WsUrl;
                    this.MessageCenter.MessageDbName = this.MessageDbName;

                    this.MessageCenter.VerifyAccount -= new VerifyAccountEventHandler(MessageCenter_VerifyAccount); // 2008/6/6 
                    this.MessageCenter.VerifyAccount += new VerifyAccountEventHandler(MessageCenter_VerifyAccount);

                    if (this.BatchTasks == null)
                        this.BatchTasks = new BatchTaskCollection();    // Close() 的时候会设置为 null。因此这里要准备重新 new

                    // 启动批处理任务
                    // TODO: 这一段考虑分离到一个函数中
                    if (bReload == false)
                    {
                        string strBreakPoint = "";

#if LOG_INFO
                        app.WriteErrorLog("INFO: DefaultThread");
#endif
                        // 启动DefaultThread
                        try
                        {
                            DefaultThread defaultThread = new DefaultThread(this, null);
                            this.BatchTasks.Add(defaultThread);

                            defaultThread.StartWorkerThread();

                            this.defaultManagerThread = defaultThread;
                        }
                        catch (Exception ex)
                        {
                            app.WriteErrorLog("启动后台任务 DefaultThread 时出错:" + ex.Message);
                            goto ERROR1;
                        }

#if LOG_INFO
                        app.WriteErrorLog("INFO: OperLogThread");
#endif
                        // 启动 OperLogThread
                        try
                        {
                            OperLogThread thread = new OperLogThread(this, null);
                            this.BatchTasks.Add(thread);

                            thread.StartWorkerThread();

                            this.operLogThread = thread;
                        }
                        catch (Exception ex)
                        {
                            app.WriteErrorLog("启动后台任务 OperLogThread 时出错:" + ex.Message);
                            goto ERROR1;
                        }

#if LOG_INFO
                        app.WriteErrorLog("INFO: ArriveMonitor");
#endif
                        // 启动ArriveMonitor
                        try
                        {
                            ArriveMonitor arriveMonitor = new ArriveMonitor(this, null);
                            this.BatchTasks.Add(arriveMonitor);

                            arriveMonitor.StartWorkerThread();
                        }
                        catch (Exception ex)
                        {
                            app.WriteErrorLog("启动批处理任务ArriveMonitor时出错:" + ex.Message);
                            goto ERROR1;
                        }

#if LOG_INFO
                        app.WriteErrorLog("INFO: ReadersMonitor");
#endif
                        // 启动ReadersMonitor
                        try
                        {
                            ReadersMonitor readersMonitor = new ReadersMonitor(this, null);
                            this.BatchTasks.Add(readersMonitor);

                            readersMonitor.StartWorkerThread();
                        }
                        catch (Exception ex)
                        {
                            app.WriteErrorLog("启动批处理任务ReadersMonitor时出错:" + ex.Message);
                            goto ERROR1;
                        }

#if LOG_INFO
                        app.WriteErrorLog("INFO: MessageMonitor");
#endif
                        // 启动MessageMonitor
                        try
                        {
                            MessageMonitor messageMonitor = new MessageMonitor(this, null);
                            this.BatchTasks.Add(messageMonitor);

                            // 从断点记忆文件中读出信息
                            // return:
                            //      -1  error
                            //      0   file not found
                            //      1   found
                            nRet = ReadBatchTaskBreakPointFile(messageMonitor.DefaultName,
                                out strBreakPoint,
                                out strError);
                            if (nRet == -1)
                            {
                                app.WriteErrorLog("ReadBatchTaskBreakPointFile时出错:" + strError);
                            }

                            if (messageMonitor.StartInfo == null)
                                messageMonitor.StartInfo = new BatchTaskStartInfo();   // 按照缺省值来

                            // 如果需要从断点启动
                            if (nRet == 1)
                                messageMonitor.StartInfo.Start = "!breakpoint";  //strBreakPoint;

                            messageMonitor.ClearProgressFile();   // 清除进度文件内容
                            messageMonitor.StartWorkerThread();
                        }
                        catch (Exception ex)
                        {
                            app.WriteErrorLog("启动批处理任务MessageMonitor时出错:" + ex.Message);
                            goto ERROR1;
                        }

                        // 启动DkywReplication
                        // <dkyw>
                        node = this.LibraryCfgDom.DocumentElement.SelectSingleNode("dkyw") as XmlElement;
                        if (node != null)
                        {
#if LOG_INFO
                            app.WriteErrorLog("INFO: DkywReplication");
#endif
                            try
                            {
                                DkywReplication dkyw = new DkywReplication(this, null);
                                this.BatchTasks.Add(dkyw);

                                /*
                                // 从断点记忆文件中读出信息
                                // return:
                                //      -1  error
                                //      0   file not found
                                //      1   found
                                nRet = ReadBatchTaskBreakPointFile(dkyw.DefaultName,
                                    out strBreakPoint,
                                    out strError);
                                if (nRet == -1)
                                {
                                    app.WriteErrorLog("ReadBatchTaskBreakPointFile时出错:" + strError);
                                }
                                 * */
                                bool bLoop = false;
                                string strLastNumber = "";

                                // return:
                                //      -1  出错
                                //      0   没有找到断点信息
                                //      1   找到了断点信息
                                nRet = dkyw.ReadLastNumber(
                                    out bLoop,
                                    out strLastNumber,
                                    out strError);
                                if (nRet == -1)
                                {
                                    app.WriteErrorLog("ReadLastNumber时出错:" + strError);
                                }

                                if (dkyw.StartInfo == null)
                                    dkyw.StartInfo = new BatchTaskStartInfo();   // 按照缺省值来

                                if (bLoop == true)
                                {
                                    // 需要从断点启动
                                    if (nRet == 1)
                                        dkyw.StartInfo.Start = "!breakpoint";  //strBreakPoint;

                                    dkyw.ClearProgressFile();   // 清除进度文件内容
                                    dkyw.StartWorkerThread();
                                }
                            }
                            catch (Exception ex)
                            {
                                app.WriteErrorLog("启动批处理任务DkywReplication时出错:" + ex.Message);
                                goto ERROR1;
                            }
                        }

                        // 启动PatronReplication
                        // <patronReplication>
                        // 读者库数据同步 批处理任务
                        // 从卡中心同步读者数据
                        node = this.LibraryCfgDom.DocumentElement.SelectSingleNode("patronReplication") as XmlElement;
                        if (node != null)
                        {
#if LOG_INFO
                            app.WriteErrorLog("INFO: PatronReplication");
#endif
                            try
                            {
                                PatronReplication patron_rep = new PatronReplication(this, null);
                                this.BatchTasks.Add(patron_rep);

                                patron_rep.StartWorkerThread();
                            }
                            catch (Exception ex)
                            {
                                app.WriteErrorLog("启动批处理任务PatronReplication时出错:" + ex.Message);
                                goto ERROR1;
                            }
                        }

                        // 启动 LibraryReplication

#if LOG_INFO
                        app.WriteErrorLog("INFO: LibraryReplication ReadBatchTaskBreakPointFile");
#endif
                        // 从断点记忆文件中读出信息
                        // return:
                        //      -1  error
                        //      0   file not found
                        //      1   found
                        nRet = ReadBatchTaskBreakPointFile("dp2Library 同步",
                            out strBreakPoint,
                            out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog("ReadBatchTaskBreakPointFile() 时出错:" + strError);
                        }
                        // 如果nRet == 0,表示没有断点文件存在,也就不必自动启动这个任务

                        // strBreakPoint 并未被使用。而是断点文件是否存在,这一信息有价值。

                        if (nRet == 1)
                        {
#if LOG_INFO
                            app.WriteErrorLog("INFO: LibraryReplication");
#endif
                            try
                            {

                                // 从断点文件中取出断点字符串
                                // 断点字符串格式:序号.偏移量@日志文件名
                                //  或者:序号@日志文件名
                                // 获得断点信息的整个过程的代码,是否适宜归入TraceDTLP类?
                                // 如果成熟,可以归纳作为BatchTask基类的一个特性。

                                LibraryReplication replication = new LibraryReplication(this, null);
                                this.BatchTasks.Add(replication);

                                if (replication.StartInfo == null)
                                    replication.StartInfo = new BatchTaskStartInfo();   // 按照缺省值来
                                replication.StartInfo.Start = "date=continue";  // 从断点开始做
                                replication.ClearProgressFile();   // 清除进度文件内容
                                replication.StartWorkerThread();
                            }
                            catch (Exception ex)
                            {
                                app.WriteErrorLog("启动批处理任务时出错:" + ex.Message);
                                goto ERROR1;
                            }
                        }

                        // 启动 RebuildKeys

#if LOG_INFO
                        app.WriteErrorLog("INFO: RebuildKeys ReadBatchTaskBreakPointFile");
#endif
                        // 从断点记忆文件中读出信息
                        // return:
                        //      -1  error
                        //      0   file not found
                        //      1   found
                        nRet = ReadBatchTaskBreakPointFile("重建检索点",
                            out strBreakPoint,
                            out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog("ReadBatchTaskBreakPointFile() 时出错:" + strError);
                        }
                        // 如果nRet == 0,表示没有断点文件存在,也就不必自动启动这个任务

                        // strBreakPoint 并未被使用。而是断点文件是否存在,这一信息有价值。

                        if (nRet == 1)
                        {
#if LOG_INFO
                            app.WriteErrorLog("INFO: RebuildKeys");
#endif
                            try
                            {

                                // 从断点文件中取出断点字符串
                                RebuildKeys replication = new RebuildKeys(this, null);
                                this.BatchTasks.Add(replication);

                                if (replication.StartInfo == null)
                                    replication.StartInfo = new BatchTaskStartInfo();   // 按照缺省值来
                                replication.StartInfo.Start = "dbnamelist=continue";  // 从断点开始做
                                replication.ClearProgressFile();   // 清除进度文件内容
                                replication.StartWorkerThread();
                            }
                            catch (Exception ex)
                            {
                                app.WriteErrorLog("启动批处理任务时出错:" + ex.Message);
                                goto ERROR1;
                            }
                        }
                    }

                    // 公共查询最大命中数
                    {
                        XmlNode nodeTemp = this.LibraryCfgDom.DocumentElement.SelectSingleNode("//virtualDatabases");
                        if (nodeTemp != null)
                        {
                            try
                            {
                                string strMaxCount = DomUtil.GetAttr(nodeTemp, "searchMaxResultCount");
                                if (String.IsNullOrEmpty(strMaxCount) == false)
                                    this.SearchMaxResultCount = Convert.ToInt32(strMaxCount);
                            }
                            catch
                            {
                            }
                        }
                    }


#if NO
            if (bReload == false)
            {
                PathUtil.CreateDirIfNeed(strColumnDir);	// 确保目录创建
                nRet = LoadCommentColumn(
                    PathUtil.MergePath(strColumnDir, "comment"),
                    out strError);
                if (nRet == -1)
                {
                    app.WriteErrorLog("装载栏目存储时出错: " + strError);
                }
            }
#endif

                    // 升级library.xml文件版本
                    if (bReload == false)
                    {
#if LOG_INFO
                        app.WriteErrorLog("INFO: UpgradeLibraryXml");
#endif
                        nRet = this.UpgradeLibraryXml(out strError);
                        if (nRet == -1)
                        {
                            app.WriteErrorLog("升级library.xml时出错:" + strError);
                        }
                    }

                    if (bReload == true)
                        app.WriteErrorLog("library application结束重新装载 " + this.m_strFileName);
                    else
                    {
                        TimeSpan delta = DateTime.Now - start;
                        app.WriteErrorLog("library application成功初始化。初始化操作耗费时间 " + delta.TotalSeconds.ToString() + " 秒");

                        // 写入down机检测文件
                        app.WriteAppDownDetectFile("library application成功初始化。");

                        if (this.watcher == null)
                        {
#if LOG_INFO
                            app.WriteErrorLog("INFO: BeginWatcher");
#endif

                            BeginWatcher();
#if LOG_INFO
                            app.WriteErrorLog("INFO: End BeginWatcher");
#endif
                        }

#if NO
                if (this.virtual_watcher == null)
                    BeginVirtualDirWatcher();
#endif
                    }

                    if (this.MaxClients != 255) // 255 通道情况下不再检查版本失效日期 2016/11/3
                    {
                        DateTime expire = new DateTime(2017, 3, 1); // 上一个版本是 2016/11/1
                        if (DateTime.Now > expire)
                        {
                            if (this.MaxClients == 255)
                            {
                                this.WriteErrorLog("*** 当前 dp2library 版本已于 " + expire.ToLongDateString() + " 失效。请系统管理员注意主动升级 dp2library");
                            }
                            else
                            {
                                // 通知系统挂起
                                // this.HangupReason = HangupReason.Expire;
                                app.AddHangup("Expire");
                                this.WriteErrorLog("*** 当前 dp2library 版本因为长期没有升级,已经失效。系统被挂起。请立即升级 dp2library 到最新版本");
                            }
                        }
                    }
                    else
                        this.WriteErrorLog("*** 特殊版本不检查失效日期。请系统管理员注意每隔半年主动升级一次 dp2library");

                    // 2013/4/10
                    if (this.Changed == true)
                        this.ActivateManagerThread();
                }
                catch (Exception ex)
                {
                    strError = "LoadCfg() 抛出异常: " + ExceptionUtil.GetDebugText(ex);
                    goto ERROR1;
                }

                return 0;
            }
            finally
            {
                // this.m_lock.ReleaseWriterLock();
                this.UnlockForWrite();
            }
        // 2008/10/13 
        ERROR1:
            if (bReload == false)
            {
                if (this.watcher == null)
                {
#if LOG_INFO
                    app.WriteErrorLog("INFO: BeginWatcher");
#endif

                    BeginWatcher();
#if LOG_INFO
                    app.WriteErrorLog("INFO: End BeginWatcher");
#endif
                }
#if NO
                if (this.virtual_watcher == null)
                    BeginVirtualDirWatcher();
#endif

            }

            if (bReload == true)
                app.WriteErrorLog("library application重新装载 " + this.m_strFileName + " 的过程发生严重错误 [" + strError + "],服务处于残缺状态,请及时排除故障后重新启动");
            else
            {
                // app.HangupReason = LibraryServer.HangupReason.StartingError;
                app.AddHangup("StartingError");
                app.WriteErrorLog("library application初始化过程发生严重错误 [" + strError + "],当前此服务处于残缺状态,请及时排除故障后重新启动");
            }
            return -1;
        }
Пример #3
0
        // 清除长期不活动的 Person 对象,顺便写入统计信息
        // 尽早写入统计信息,可以减少意外 Down 掉的丢失写入的损害
        public void CleanPersons(TimeSpan delta, 
            Statis statis)
        {
            // List<string> remove_keys = new List<string>();

            List<Person> remove_persons = new List<Person>();   // 需要清除的对象
            List<Person> flush_persons = new List<Person>();    // 需要写入统计数据的对象

            // 读锁定并不阻碍一般性访问
            if (this.m_lock.TryEnterReadLock(m_nLockTimeout) == false)
                throw new ApplicationException("锁定尝试中超时");
            try
            {
                foreach (string key in this.Keys)
                {
                    Person person = (Person)this[key];

                    if (person == null)
                        continue;

                    if ((DateTime.Now - person.LastUsedTime) >= delta)
                    {
                        // remove_keys.Add(key);   // 这里不能删除,因为 foreach 还要用枚举器
                        remove_persons.Add(person);
                    }
                    else if (person.StatisWrited == false)
                    {
                        flush_persons.Add(person);
                    }
                }
            }
            finally
            {
                this.m_lock.ExitReadLock();
            }

#if NO
            if (remove_keys.Count == 0)
                return;
#endif
            // 移走过期的对象
            if (remove_persons.Count > 0)
            {

                // 因为要删除某些元素,所以用写锁定
                List<Person> delete_persons = new List<Person>();
                if (this.m_lock.TryEnterWriteLock(m_nLockTimeout) == false)
                    throw new ApplicationException("锁定尝试中超时");
                try
                {
#if NO
                    foreach (string key in remove_keys)
                    {
                        Person person = (Person)this[key];
                        if (person == null)
                            continue;   // sessionid 没有找到对应的 Session 对象

                        // 和 id 的 hashtable 脱离关系
                        this.Remove(key);

                        delete_persons.Add(person);
                    }
#endif
                    foreach (Person person in remove_persons)
                    {
                        this.Remove(person.ID);
                    }
                }
                finally
                {
                    this.m_lock.ExitWriteLock();
                }
            }

            // 写入统计信息
            if (statis != null)
            {
                foreach (Person person in remove_persons)
                {
                    // TODO: 可以按照馆代码统计聚类后,减少写入 Statis 的次数
                    if (person.StatisWrited == false)
                    {
                        // 增量统计数
                        statis.IncreaseEntryValue(
                        person.LibraryCode,
                        "出纳",
                        "读者数",
                        1);
                        person.StatisWrited = true;
                        // person.Close();
                    }
                }

                foreach (Person person in flush_persons)
                {
                    if (person.StatisWrited == false)
                    {
                        // 增量统计数
                        statis.IncreaseEntryValue(
                        person.LibraryCode,
                        "出纳",
                        "读者数",
                        1);
                        person.StatisWrited = true;
                        // person.Close();
                    }
                }
            }
        }
Пример #4
0
        public void Close()
        {
            _app_down.Cancel();

            this.EndWather();

            //this.HangupReason = LibraryServer.HangupReason.Exit;    // 阻止后继 API 访问
            this.AddHangup("Exit");

            this.WriteErrorLog("LibraryApplication 开始下降");

            DateTime start = DateTime.Now;
            try
            {
                // 停止所有长操作
                this.StopAll();

                // 2014/12/3
                this.Flush();

                if (this.OperLog != null)
                {
                    this.OperLog.Close(true);   // 自动进入小文件模式,对象依然有效
                    // this.OperLog = null; // 对象不要释放,依然起作用
                }

                if (this.Garden != null)
                {
                    // 紧急写入所有统计指标
                    this.Garden.CleanPersons(new TimeSpan(0, 0, 0), this.Statis);
                    this.Garden = null;
                }

                if (this.Statis != null)
                {
                    this.Statis.Close();
                    this.Statis = null;
                }

                /*
                if (this.ArriveMonitor != null)
                    this.ArriveMonitor.Close();
                 * */
                if (this.BatchTasks != null)
                {
                    this.BatchTasks.Close();
                    this.BatchTasks = null;
                }

            }
            catch (Exception ex)
            {
                this.WriteErrorLog("LibraryApplication Close()俘获异常: " + ExceptionUtil.GetDebugText(ex));
            }

            TimeSpan delta = DateTime.Now - start;
            this.WriteErrorLog("LibraryApplication 被停止。停止操作耗费时间 " + delta.TotalSeconds.ToString() + " 秒");

            this.RemoveAppDownDetectFile();	// 删除检测文件

            disposed = true;
        }