LevelDB 在删除 LevelDB 实例时断言

LevelDB asserts when deleting the LevelDB instance

本文关键字:LevelDB 断言 删除 实例      更新时间:2023-10-16

当我尝试删除 leveldb 实例时,我得到了一些非常烦人的断言,但我不确定为什么会发生这种情况!

断言发生在 version_set.cc 文件中:

void VersionSet::AppendVersion(Version* v) {
  // Make "v" current
  assert(v->refs_ == 0); // <---??? how do I avoid this assertion?
  // the rest of the source code is available in the link to version_set.cc
}

此外,它在同一文件的另一个位置断言:

Version::~Version() {
  assert(refs_ == 0); // <-- Again... how do I avoid this one too?
  // the rest of the source code is available in the link to version_set.cc
}

以下是有关我系统中使用情况的更多背景详细信息,我有一个:

  • ExtStorage(扩展存储(,具有LevelDB::DB实例。
  • EextStorageDotNet ,它是围绕ExtStorage的 C++/CLI 包装器。
  • AltStorage ,它包含指向 ExtStorage 类(通过构造函数传递(的指针:
  • AltStorageDotNet ,它是围绕AltStorage的 C++/CLI 包装器。

备用存储类如下所示:

class AltStorage{
    ExtStorage* instance;
public:
    AltStorage(ExtStorage* extStorage):instance(extStorage){}
    ~AltStorage(){
        delete instance;
        instance = NULL;
    }
};

ExtStorage类如下所示:

class ExtStorage{
    leveldb::DB* mydb;
public:
    ExtStorage(/*some parameters*/){
         mydb = new leveldb::DB(/*parameters*/);
    }
    // Destructor
    ~ExtStorage() {
        Close();
    }
    // deletes the leveldb::DB instance
    void Close() {
        if(mydb == NULL) {
            delete mydb; // <-- Asserts every time I get here when using with the AltStorageDotNet
            mydb= NULL;
            // Close the L1 and L2 caches
            // only once (
        }
    }
}

AltStorageDotNet类如下所示:

public ref class AltStorageDotNet{
    AltStorage* altInstance;
    ExtStorageDotNet^ extInstance;
public:
    AltStorageDotNet() {
        ExtStorage extStorage = new ExtStorage(/*params*/);
        altInstance = new AltStorage(extStorage);
        extInstance = gcnew ExtStorageDotNet(extStorage);
    }
    ~AltStorageDotNet(){
        delete altInstance;
        altInstance = NULL;
        // no need to delete extInstance since it was created with gcnew 
    }
    !AltStorageDotNet(){
        delete altInstance;
        altInstance = NULL;
        // no need to delete extInstance since it was created with gcnew
    }
    inline ExtStorageDotNet^ GetExtInstance(){return extInstance;}
};

DotNet 包装器如下所示:

public ref class ExtStorageDotNet{
private:
    ExtStorage* instance;
public:
    ExtStorageDotNet(ExtStorage* extStorage){
        instance = extStorage;
    }
    ~ExtStorageDotNet(){
        delete instance;
        instance = NULL;
    }
    !ExtStorageDotNet(){
        delete instance;
        instance = NULL;
    }
    void Close(){instance->Close();}
};

每当我在 C# 应用程序中使用 ExtStorageDotNet 包装器时,一切正常,并且没有断言。但是,当我使用 AltStorageDotNet 包装器并访问 ExtStorageDotNet 包装器时,我会在关闭数据库时获得断言。这都是测试套件的一部分,我在其中为每个测试用例初始化一个实例,并在每个测试用例后关闭它;在新测试用例开始之前,关联的数据库文件将被删除。我看不出有任何理由应该发生这种情况,并且断言无助于追踪问题。

我摆脱了嵌套引用,但这并没有解决问题。事实证明,导致此问题的问题并不完全是我所关注的。当用户获取数据库的迭代器,并且无法在删除数据库之前删除迭代器时,会出现此问题。这在与级别数据库相关的谷歌组中进行了讨论。

// Caller should delete the iterator when it is no longer needed.
// The returned iterator should be deleted before this db is deleted.
virtual Iterator* NewIterator(const ReadOptions& options) = 0; 

当用户获得迭代器时,他们应该在删除数据库之前将其删除,否则他们将获得上述断言。

我不知道

它是否与您的断言有关,但这段代码肯定会导致内存损坏。ExtStorageDotNetAltStorageDotNet都是一次性的和可定稿的,并且(直接或间接地(delete ExtStorage的实例 - 总是,一个会在另一个已经有之后delete它。

另外,正如我在评论中所说,您的代码中的注释说no need to delete extInstance since it was created with gcnew很不对劲 - 有关详细信息,请参阅此答案。(我假设你知道C#,因此了解IDisposable;如果你不了解,那么你真的需要做一些阅读。