删除LevelDB实例时LevelDB断言

时间:2011-08-17 23:10:44

标签: c++ c++-cli assert assertions leveldb

当我尝试删除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个实例。
  • class EextStorageDotNet,它是ExtStorage周围的C ++ / CLI包装器。
  • class AltStorage,它包含一个指向ExtStorage类的指针(通过构造函数传递):
  • class 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包装器时,我在关闭数据库时得到断言。 这是测试套件的所有部分,我在其中为每个测试用例初始化一个实例并在每个测试用例之后关闭它;在新的测试用例开始之前,相关的数据库文件会被删除。我没有看到为什么会发生这种情况的原因,并且断言对跟踪问题没有帮助。

2 个答案:

答案 0 :(得分:2)

我摆脱了嵌套引用,但这并没有解决问题。事实证明,导致这个问题的问题并不是我所看到的。当用户获取数据库的迭代器并且在删除数据库之前无法删除迭代器时,会出现此问题。这在google group relating to level db中进行了讨论。

// 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; 

当用户获取迭代器时,他们应该在删除db之前将其删除,否则他们将得到上面提到的断言。

答案 1 :(得分:1)

我不知道它是否与你的断言有关,但是这段代码可以保证会导致内存损坏。 ExtStorageDotNetAltStorageDotNet都是一次性的并且可以最终确定,并且{直接或间接地} delete ExtStorage的实例 - 总是会delete之后no need to delete extInstance since it was created with gcnew另一个已经有了。

另外,正如我在评论中所说,您的代码中的评论IDisposable已取消 - 请参阅this answer了解详情。 (我假设你知道C#,因此关于{{1}};如果你不知道,那么你真的需要做一些阅读。)