0

我有一个"Vulcan.edb"从正在使用的应用程序复制的 ESE 数据库 ( )。自然,这意味着数据库处于“脏关机”状态。幸运的是,我确实有数据库的日志文件("V01.log"),根据我能找到的每个 类似 问题,我应该能够附加数据库并让引擎恢复它。这是我用来附加数据库的代码,使用托管 ESE API(非托管 C++ 端口应该是微不足道的):

public void ReadFromDatabase(string fileName, string logFileBaseName)
{
    string databaseDirectory = Path.GetDirectoryName(fileName);

    int pageSize;
    Api.JetGetDatabaseFileInfo(fileName, out pageSize, JET_DbInfo.PageSize);
    Api.JetSetSystemParameter(JET_INSTANCE.Nil, JET_SESID.Nil, JET_param.DatabasePageSize, pageSize, null);

    Api.JetSetSystemParameter(JET_INSTANCE.Nil, JET_SESID.Nil, JET_param.Recovery, 0, "Off");

    JET_INSTANCE jetInstance;
    string jetInstanceName = Guid.NewGuid().ToString("N");
    Api.JetCreateInstance(out jetInstance, jetInstanceName);

    Api.JetSetSystemParameter(jetInstance, JET_SESID.Nil, JET_param.BaseName, 0, logFileBaseName);
    Api.JetSetSystemParameter(jetInstance, JET_SESID.Nil, JET_param.LogFilePath, 0, databaseDirectory);
    Api.JetSetSystemParameter(jetInstance, JET_SESID.Nil, JET_param.TempPath, 0, databaseDirectory);
    Api.JetSetSystemParameter(jetInstance, JET_SESID.Nil, JET_param.SystemPath, 0, databaseDirectory);
    Api.JetSetSystemParameter(jetInstance, JET_SESID.Nil, Microsoft.Isam.Esent.Interop.Server2003.Server2003Param.AlternateDatabaseRecoveryPath, 0, databaseDirectory);
    try
    {
        Api.JetInit(ref jetInstance);

        JET_SESID sessionId;
        Api.JetBeginSession(jetInstance, out sessionId, "admin", "");

        try
        {
            Api.JetAttachDatabase(sessionId, fileName, AttachDatabaseGrbit.ReadOnly);

            JET_DBID databaseId;
            Api.JetOpenDatabase(sessionId, fileName, "", out databaseId, OpenDatabaseGrbit.ReadOnly);

            // Do other stuff here...

            Api.JetCloseDatabase(sessionId, databaseId, CloseDatabaseGrbit.None);
        }
        finally
        {
            Api.JetEndSession(sessionId, EndSessionGrbit.None);
        }
    }
    finally
    {
        Api.JetTerm(jetInstance);
    }
}

实际上,如果我将数据库文件和日志文件都复制到<directory of database>并运行 edbntutl.exe /r V01 /l <directory of database> /s <directory of database> /d <directory of database>,则数据库在我的代码中变得可用和可附加。但是,如果我不采取手动恢复数据库的步骤,我的代码调用失败JetAttachDatabase,错误为JET_errDatabaseDirtyShutdown.

那么为什么我的代码不能自动恢复数据库呢?要么edbntutl正在做一些未记录的事情,要么我在会话配置中遗漏了一些东西以允许引擎恢复数据库。虽然前者不是不可能的,但如果是这样的话,那将是非常不幸的,而且我倾向于相信我只是错过了一些东西。

注意:如果没有证据表明实用程序正在执行公共 API 中不可用的操作,则不会接受相当于“在运行代码之前运行 esentutil”的答案。

4

1 回答 1

0

您需要做很多事情来稳健地处理 esent dbs 的加载。以下是 RavenDB 代码库中处理脏关机所需的相关代码:

https://github.com/ravendb/ravendb/blob/552208aed679f4a3936a57f9a7506568657e291e/Raven.Database/Storage/Esent/TransactionalStorage.cs#L721-L736

于 2018-03-01T07:56:51.417 回答