Boost logo

Boost Users :

Subject: Re: [Boost-users] multi_index_container assertion after crash
From: Eli Zakashansky (Eli.Zakashansky_at_[hidden])
Date: 2010-01-04 12:25:00


Hello,

After asking my question the first time (a few month ago) Andrew and Joaquín both tried to help me, but unfortunately I still didn't find problem's root cause / solution. Partially it might be because I did not supplied enough information therefore I wrote a short-simple-single threaded console app that might help you reproduce the problem / find my mistake (this of course not a production app therefore there are a lot of hard-coded constants etc.).

The apps code contains 3 files " BoostTestingApp.cpp", " DataContainer.h", and "DataContainer.cpp" which could be found below.

But first the instructions:

To create the "damaged" data file use the following input:
2 (insert)
-1 (maximum)
5 (empty) - during this operation kill proc manually from the program manager (yes I am using windows) which simulates the crush.

To reproduce the problem (assertion window pops up) use the following inputs (restart the app using debug after creating the damaged file) :

Input #1:
4 (delete all)

Input #2:
3 (delete)
500000 (this particular record)

The program :

BoostTestingApp.cpp
------------------

#include "stdafx.h"
#include "DataContainer.h"
#include <iostream>
#include <stdlib.h>
using namespace std;

int ID;

void insert(CDataContainer* dataContainer)
{
        cout<<"how many rows"<<endl;
        int rows;
        cin>>rows;
        rows = (rows==-1)?1300000:rows;
        bool success = true;
        for (int i=0;i<rows && success;i++)
        {
                DataBasicStructure data;
                data.id = ID;
                data.key2 = ID/2;
                data.key3 = ID/3;
                data.key4 = ID/4;
                data.key5 = ID/5;
                itoa(data.id, data.text, 3);
                success = dataContainer->Insert(data);
                ID++;
        }
        if (success)
        {
                cout<<"command finished successfully"<<endl;
        }
}
void deleteS(CDataContainer* dataContainer)
{
        DataEntry entry;
        DataKey key;
        cout<<"which ID to delete"<<endl;
        cin>>key.id;
        if (dataContainer->GetAndDelete(key,&entry,true))
                cout<<"command finished successfully"<<endl;
        cout<<"key5 :"<<entry.Key5()<<endl;
}

void empty(CDataContainer* dataContainer)
{
        DataEntry entry;
        DataKey key;
        while ((int)dataContainer->m_dataTable->size()!=0)
        {
                CDataContainer::MainIDIndex& idx= dataContainer->m_dataTable->get<MAIN_ID>();
                CDataContainer::MainIDIndex::const_iterator it = idx.begin();
                dataContainer->m_dataTable->erase(it);
        }

        cout<<"command finished successfully"<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
        ID = 0;
        CDataContainer* dataContainer = new CDataContainer();
        dataContainer->Initialize();
        int option;
        int max_size =0;
        bool loop = true;
        while (loop)
        {
                cout<<"options:"<<endl<<"1: get current size"<<endl<<"2: insert"<<endl<<"3: delete"<<endl<<"4: delete all"<<endl<<"5: empty"<<endl<<"6: exit"<<endl;
                cin>>option;
                switch(option)
                {
                case 1:
                        cout<<"current size : "<<(int)dataContainer->m_dataTable->size()<<endl;
                        break;
                case 2:
                        insert(dataContainer);
                        break;
                case 3:
                        deleteS(dataContainer);
                        break;
                case 4:
                        dataContainer->m_dataTable->clear();
                        cout<<"finished"<<endl;
                        break;
                case 5:
                        empty(dataContainer);
                        break;
                case 7:
                        max_size = 50*1024*1024;
                        max_size /= sizeof(DataBasicStructure);
                        cout<<"max size = "<<max_size;
                default:
                case 6:
                        cout<<":)"<<endl;
                        loop = false;
                        break;
                }
        }
        delete dataContainer;
        return 0;
}

DataContainer.h
---------------

#pragma once

#if !defined(NDEBUG)
//#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/composite_key.hpp>

#include "Windows.h"
#include "stdafx.h"
using boost::multi_index_container;
using namespace boost::multi_index;

typedef struct
{
        int id;//key1
        int key2;
        int key3;
        int key4;
        int key5;
        char text[20];
}
DataBasicStructure;

struct DataKey
{
        DataKey(){}
        DataKey(int pid):id(pid){}
        int id;
};

struct DataEntry{
        DataBasicStructure data;

        int ID()const
        {
                return data.id;
        }
        
        int Key2()const
        {
                return data.key2;
        }

        int Key3()const
        {
                return data.key3;
        }

        int Key4()const
        {
                return data.key4;
        }

        int Key5()const
        {
                return data.key5;
        }

        char Text() const
        {
                return data.text[0];
        }
};

class ContainerLocker;

typedef indexed_by<
ordered_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN(DataEntry,int,ID)>,
ordered_non_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN(DataEntry,int,Key2)>,
ordered_non_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN(DataEntry,int,Key3)>,
ordered_non_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN(DataEntry,int,Key4)>,
ordered_non_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN(DataEntry,int,Key5)>>
ContainerIndexSpecifierList;
typedef boost::interprocess::allocator<DataBasicStructure,boost::interprocess::managed_mapped_file::segment_manager> ContainerAllocator;
typedef multi_index_container<DataEntry, ContainerIndexSpecifierList, ContainerAllocator> data_container;

#define MAIN_ID 0
#define KEY_2 1
#define KEY_3 2
#define KEY_4 3
#define KEY_5 4

typedef nth_index_iterator<data_container,MAIN_ID>::type Data_Iterator;

class CDataContainer
{
public:
        typedef nth_index<data_container,MAIN_ID>::type MainIDIndex;
        typedef nth_index<data_container,KEY_2>::type Key2Index;
        typedef nth_index<data_container,KEY_3>::type Key3Index;
        typedef nth_index<data_container,KEY_4>::type Key4Index;
        typedef nth_index<data_container,KEY_5>::type Key5Index;

        bool m_isInitialized;
        long DataTableMaxEntries;
        boost::interprocess::managed_mapped_file *m_containerMapFile;
        data_container *m_dataTable;
        bool Init(const char *fileName);
        void BackUpFile( const char * fileName );
        class IteratorLocation
        {
                friend class CDataContainer;
        public:
                bool regetRange;
                IteratorLocation() { regetRange = true; }
                std::pair<MainIDIndex::iterator, MainIDIndex::iterator> m_MainIDIterator;
                std::pair<Key2Index::iterator, Key2Index::iterator> m_key2Iterator;
                std::pair<Key3Index::iterator, Key3Index::iterator> m_key3Iterator;
                std::pair<Key4Index::iterator, Key4Index::iterator> m_key4Iterator;
                std::pair<Key5Index::iterator, Key5Index::iterator> m_key5Iterator;
        };

        BOOL Initialize();
        bool Insert( const DataBasicStructure &data);
        bool GetAndDelete(DataKey key, DataEntry *data, bool del);
};

DataContainer.cpp
-----------------
#include "DataContainer.h"

bool CDataContainer::Init( IN const char *fileName)
{
        bool returnStatus = true;
        int count = 0;
        int dataRequiredSize = DataTableMaxEntries*sizeof(DataEntry);
        dataRequiredSize += ((int)(0.1*dataRequiredSize) > 100*1024*1024) ? (int)(0.1*dataRequiredSize) : 100*1024*1024;
        dataRequiredSize *= 3;
        try
        {
                m_containerMapFile = new boost::interprocess::managed_mapped_file(boost::interprocess::open_only,fileName);
                bool suc = true;
                suc &= (m_containerMapFile != NULL);
                suc &= (m_containerMapFile->get_size()== dataRequiredSize);
                suc &= m_containerMapFile->check_sanity();
                if (suc)
                {
                        bool initSucceed = true;

                        m_dataTable = m_containerMapFile->find_or_construct<data_container>(fileName)(
                                data_container::ctor_args_list(),
                                data_container::allocator_type(m_containerMapFile->get_segment_manager()));

                        if (NULL!=m_dataTable)
                        {
                                if (m_dataTable->size() > DataTableMaxEntries)
                                        m_containerMapFile = NULL;
                        }

                        initSucceed = (NULL!=m_containerMapFile)?true:false;

                        if (!initSucceed)
                                m_containerMapFile = NULL;
                }
                else
                        m_containerMapFile = NULL;
        }
        catch (...)
        {
                m_containerMapFile = NULL;
        }
        try
        {
                if (m_containerMapFile == NULL)
                {
                        std::string backupFile(fileName);
                        backupFile.append("_bak");
                        remove(backupFile.c_str());
                        rename(fileName, backupFile.c_str());
                        m_containerMapFile = new boost::interprocess::managed_mapped_file(
                                boost::interprocess::create_only,fileName,
                                dataRequiredSize);
                        m_dataTable = m_containerMapFile->construct<data_container>(fileName)(
                                data_container::ctor_args_list(),
                                data_container::allocator_type(m_containerMapFile->get_segment_manager()));
                }
                m_isInitialized = true;
        }
        catch (...)
        {
                m_isInitialized = false;
                returnStatus = false;
        }
        return returnStatus;
}

void CDataContainer::BackUpFile( const char * fileName )
{
        std::string backupFile(fileName);
        backupFile.append("_bak");
        remove(backupFile.c_str());
        rename(fileName, backupFile.c_str());
}

bool CDataContainer::Insert( IN const DataBasicStructure &data)
{
        bool rv = true;
        if ((int)m_dataTable->size() < DataTableMaxEntries)
        {
                DataEntry entry;
                entry.data = data;
                try
                {
                        m_dataTable->insert(entry);
                }
                catch (...)
                {
                        rv = false;
                }
        }
        else
        {
                rv = false;
        }
        return rv;
}

bool CDataContainer::GetAndDelete( DataKey key, DataEntry *data,bool del)
{
        bool rc = true;
        MainIDIndex& idx=m_dataTable->get<MAIN_ID>();
        MainIDIndex::iterator it = idx.find(key.id);
        if (it == idx.end())
                rc = false;
        else
        {
                *data = *it;
                if (del)
                {
                        idx.erase(it);
                }
        }
        return rc;
}

BOOL CDataContainer::Initialize()
{
        BOOL result = TRUE;

        DataTableMaxEntries = 1300000;

        if (Init("boost_Testing") != true)
                return FALSE;

        return result;
}

Thank you very much,
Eli.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net