|
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