Index: src/libchcore/TSQLiteTaskSchema.cpp
===================================================================
diff -u -r19925be73ffcadd9f345f10e03e55aadb3f0eeac -rff16e23b043c1c3f3ea883372b6f81d7ad4adca3
--- src/libchcore/TSQLiteTaskSchema.cpp	(.../TSQLiteTaskSchema.cpp)	(revision 19925be73ffcadd9f345f10e03e55aadb3f0eeac)
+++ src/libchcore/TSQLiteTaskSchema.cpp	(.../TSQLiteTaskSchema.cpp)	(revision ff16e23b043c1c3f3ea883372b6f81d7ad4adca3)
@@ -72,6 +72,9 @@
 		tStatement.Prepare(_T("CREATE TABLE subtasks(id BIGINT UNIQUE, type INT NOT NULL, is_current boolean NOT NULL, is_estimation boolean NOT NULL)"));
 		tStatement.Step();
 
+		tStatement.Prepare(_T("CREATE TABLE subtasks_info(id BIGINT UNIQUE, operation INT NOT NULL)"));
+		tStatement.Step();
+
 		tStatement.Prepare(_T("CREATE TABLE subtask_fastmove(id BIGINT UNIQUE, current_index INT NOT NULL, is_running boolean NOT NULL, total_size BIGINT NOT NULL, processed_size BIGINT NOT NULL, size_speed varchar(1024) NOT NULL, ")
 							_T("total_count BIGINT NOT NULL, processed_count BIGINT NOT NULL, count_speed varchar(1024) NOT NULL, ci_processed_size BIGINT NOT NULL, ci_total_size BIGINT NOT NULL, timer BIGINT NOT NULL, ")
 							_T("buffer_index INT NOT NULL, current_path varchar(32768) NOT NULL, suboperation_type INT NOT NULL)"));
Index: src/libchcore/TSubTaskArray.cpp
===================================================================
diff -u -r19925be73ffcadd9f345f10e03e55aadb3f0eeac -rff16e23b043c1c3f3ea883372b6f81d7ad4adca3
--- src/libchcore/TSubTaskArray.cpp	(.../TSubTaskArray.cpp)	(revision 19925be73ffcadd9f345f10e03e55aadb3f0eeac)
+++ src/libchcore/TSubTaskArray.cpp	(.../TSubTaskArray.cpp)	(revision ff16e23b043c1c3f3ea883372b6f81d7ad4adca3)
@@ -42,18 +42,20 @@
 
 TSubTasksArray::TSubTasksArray(TSubTaskContext& rSubTaskContext) :
 m_rSubTaskContext(rSubTaskContext),
-	m_eOperationType(eOperation_None),
+	m_eOperationType(m_setModifications, eOperation_None),
 	m_lSubOperationIndex(0),
 	m_lLastStoredIndex(-1)
 {
+	m_setModifications[eMod_Added] = true;
 }
 
 TSubTasksArray::TSubTasksArray(const TOperationPlan& rOperationPlan, TSubTaskContext& rSubTaskContext) :
 	m_rSubTaskContext(rSubTaskContext),
-	m_eOperationType(eOperation_None),
+	m_eOperationType(m_setModifications, eOperation_None),
 	m_lSubOperationIndex(0),
 	m_lLastStoredIndex(-1)
 {
+	m_setModifications[eMod_Added] = true;
 	Init(rOperationPlan);
 }
 
@@ -172,50 +174,74 @@
 
 void TSubTasksArray::Store(const ISerializerPtr& spSerializer) const
 {
-	ISerializerContainerPtr spContainer = spSerializer->GetContainer(_T("subtasks"));
-	ISerializerRowDataPtr spRow;
+	bool bAdded = m_setModifications[eMod_Added];
 
-	// base data
-	long lCurrentIndex = m_lSubOperationIndex.load(boost::memory_order_acquire);
-	bool bAdded = (m_lLastStoredIndex == -1);
-
-	// subtasks are stored only once when added as they don't change (at least in context of their order and type)
-	if(bAdded)
+	///////////////////////////////////////////////////////////////////////
 	{
-		for(size_t stSubOperationIndex = 0; stSubOperationIndex < m_vSubTasks.size(); ++stSubOperationIndex)
-		{
-			if(bAdded)
-				spRow = spContainer->AddRow(stSubOperationIndex);
+		ISerializerContainerPtr spContainer = spSerializer->GetContainer(_T("subtasks_info"));
+		ISerializerRowDataPtr spRow;
 
-			const std::pair<TSubTaskBasePtr, bool>& rCurrentSubTask = m_vSubTasks[stSubOperationIndex];
+		if(bAdded)
+			spRow = spContainer->AddRow(0);
+		else
+			spRow = spContainer->GetRow(0);
 
-			*spRow
-				% TRowData(_T("type"), rCurrentSubTask.first->GetSubOperationType())
-				% TRowData(_T("is_current"), false)
-				% TRowData(_T("is_estimation"), rCurrentSubTask.second);
-		}
+		*spRow
+			% TRowData(_T("operation"), m_eOperationType.Get());
 	}
 
-	// serialize current index
-	if(bAdded || lCurrentIndex != m_lLastStoredIndex)
+	///////////////////////////////////////////////////////////////////////
 	{
-		// mark subtask at current index as "current"; don't do that if we just finished.
-		if(lCurrentIndex != m_vSubTasks.size())
+		ISerializerContainerPtr spContainer = spSerializer->GetContainer(_T("subtasks"));
+		ISerializerRowDataPtr spRow;
+
+		// base data
+		long lCurrentIndex = m_lSubOperationIndex.load(boost::memory_order_acquire);
+
+		// subtasks are stored only once when added as they don't change (at least in context of their order and type)
+		if(bAdded)
 		{
-			spRow = spContainer->GetRow(lCurrentIndex);
-			*spRow % TRowData(_T("is_current"), true);
+			if(m_lLastStoredIndex != -1)
+				THROW_CORE_EXCEPTION(eErr_InternalProblem);
+
+			for(size_t stSubOperationIndex = 0; stSubOperationIndex < m_vSubTasks.size(); ++stSubOperationIndex)
+			{
+				if(bAdded)
+					spRow = spContainer->AddRow(stSubOperationIndex);
+
+				const std::pair<TSubTaskBasePtr, bool>& rCurrentSubTask = m_vSubTasks[stSubOperationIndex];
+
+				*spRow
+					% TRowData(_T("type"), rCurrentSubTask.first->GetSubOperationType())
+					% TRowData(_T("is_current"), false)
+					% TRowData(_T("is_estimation"), rCurrentSubTask.second);
+			}
 		}
 
-		// unmark the old "current" subtask
-		if(m_lLastStoredIndex != -1)
+		// serialize current index
+		if(bAdded || lCurrentIndex != m_lLastStoredIndex)
 		{
-			spRow = spContainer->GetRow(m_lLastStoredIndex);
-			*spRow % TRowData(_T("is_current"), false);
+			// mark subtask at current index as "current"; don't do that if we just finished.
+			if(lCurrentIndex != m_vSubTasks.size())
+			{
+				spRow = spContainer->GetRow(lCurrentIndex);
+				*spRow % TRowData(_T("is_current"), true);
+			}
+
+			// unmark the old "current" subtask
+			if(m_lLastStoredIndex != -1)
+			{
+				spRow = spContainer->GetRow(m_lLastStoredIndex);
+				*spRow % TRowData(_T("is_current"), false);
+			}
 		}
+
+		m_lLastStoredIndex = lCurrentIndex;
 	}
 
-	m_lLastStoredIndex = lCurrentIndex;
+	m_setModifications.reset();
 
+	///////////////////////////////////////////////////////////////////////
 	// store all the subtasks
 	for(size_t stSubOperationIndex = 0; stSubOperationIndex < m_vSubTasks.size(); ++stSubOperationIndex)
 	{
@@ -226,48 +252,66 @@
 
 void TSubTasksArray::Load(const ISerializerPtr& spSerializer)
 {
-	m_lLastStoredIndex = -1;
+	///////////////////////////////////////////////////////////////////////
+	{
+		ISerializerContainerPtr spContainer = spSerializer->GetContainer(_T("subtasks_info"));
+		ISerializerRowReaderPtr spRowReader = spContainer->GetRowReader();
 
-	ISerializerContainerPtr spContainer = spSerializer->GetContainer(_T("subtasks"));
-	ISerializerRowReaderPtr spRowReader = spContainer->GetRowReader();
+		IColumnsDefinitionPtr spColumns = spRowReader->GetColumnsDefinitions();
+		if(spColumns->IsEmpty())
+			*spColumns % _T("id") % _T("operation");
 
-	IColumnsDefinitionPtr spColumns = spRowReader->GetColumnsDefinitions();
-	if(spColumns->IsEmpty())
-		*spColumns % _T("id") % _T("type") % _T("is_current") % _T("is_estimation");
+		if(spRowReader->Next())
+			spRowReader->GetValue(_T("operation"), *(int*)&m_eOperationType.Modify());
+	}
 
-	while(spRowReader->Next())
+	///////////////////////////////////////////////////////////////////////
 	{
-		long lID = 0;
-		int iType = 0;
-		bool bIsCurrent = false;
-		bool bIsEstimation = false;
+		m_lLastStoredIndex = -1;
 
-		spRowReader->GetValue(_T("id"), lID);
-		spRowReader->GetValue(_T("type"), iType);
-		spRowReader->GetValue(_T("is_current"), bIsCurrent);
-		spRowReader->GetValue(_T("is_estimation"), bIsEstimation);
+		ISerializerContainerPtr spContainer = spSerializer->GetContainer(_T("subtasks"));
+		ISerializerRowReaderPtr spRowReader = spContainer->GetRowReader();
 
-		if(bIsCurrent)
+		IColumnsDefinitionPtr spColumns = spRowReader->GetColumnsDefinitions();
+		if(spColumns->IsEmpty())
+			*spColumns % _T("id") % _T("type") % _T("is_current") % _T("is_estimation");
+
+		while(spRowReader->Next())
 		{
-			m_lSubOperationIndex.store(lID, boost::memory_order_release);
-			m_lLastStoredIndex = lID;
-		}
+			long lID = 0;
+			int iType = 0;
+			bool bIsCurrent = false;
+			bool bIsEstimation = false;
 
-		// create subtask, load it and put into the array
-		TSubTaskBasePtr spSubTask = CreateSubtask((ESubOperationType)iType, m_rSubTaskContext);
-		spSubTask->Load(spSerializer);
+			spRowReader->GetValue(_T("id"), lID);
+			spRowReader->GetValue(_T("type"), iType);
+			spRowReader->GetValue(_T("is_current"), bIsCurrent);
+			spRowReader->GetValue(_T("is_estimation"), bIsEstimation);
 
-		if(lID != m_vSubTasks.size())
-			THROW_CORE_EXCEPTION(eErr_InvalidData);
+			if(bIsCurrent)
+			{
+				m_lSubOperationIndex.store(lID, boost::memory_order_release);
+				m_lLastStoredIndex = lID;
+			}
 
-		m_vSubTasks.push_back(std::make_pair(spSubTask, bIsEstimation));
-	}
+			// create subtask, load it and put into the array
+			TSubTaskBasePtr spSubTask = CreateSubtask((ESubOperationType)iType, m_rSubTaskContext);
+			spSubTask->Load(spSerializer);
 
-	if(m_lLastStoredIndex == -1)
-	{
-		m_lSubOperationIndex.store(boost::numeric_cast<long>(m_vSubTasks.size()), boost::memory_order_release);
-		m_lLastStoredIndex = boost::numeric_cast<long>(m_vSubTasks.size());
+			if(lID != m_vSubTasks.size())
+				THROW_CORE_EXCEPTION(eErr_InvalidData);
+
+			m_vSubTasks.push_back(std::make_pair(spSubTask, bIsEstimation));
+		}
+
+		if(m_lLastStoredIndex == -1)
+		{
+			m_lSubOperationIndex.store(boost::numeric_cast<long>(m_vSubTasks.size()), boost::memory_order_release);
+			m_lLastStoredIndex = boost::numeric_cast<long>(m_vSubTasks.size());
+		}
 	}
+
+	m_setModifications.reset();
 }
 
 TSubTaskBasePtr TSubTasksArray::CreateSubtask(ESubOperationType eType, TSubTaskContext& rContext)
Index: src/libchcore/TSubTaskArray.h
===================================================================
diff -u -r19925be73ffcadd9f345f10e03e55aadb3f0eeac -rff16e23b043c1c3f3ea883372b6f81d7ad4adca3
--- src/libchcore/TSubTaskArray.h	(.../TSubTaskArray.h)	(revision 19925be73ffcadd9f345f10e03e55aadb3f0eeac)
+++ src/libchcore/TSubTaskArray.h	(.../TSubTaskArray.h)	(revision ff16e23b043c1c3f3ea883372b6f81d7ad4adca3)
@@ -29,6 +29,8 @@
 #include "TTaskLocalStats.h"
 #include "TSubTaskArrayStatsSnapshot.h"
 #include <boost/atomic.hpp>
+#include "TSharedModificationTracker.h"
+#include <bitset>
 
 BEGIN_CHCORE_NAMESPACE
 
@@ -65,17 +67,32 @@
 	static TSubTaskBasePtr CreateSubtask(ESubOperationType eType, TSubTaskContext& rContext);
 
 private:
+	enum EModifications
+	{
+		eMod_Added,
+		eMod_OperationType,
+
+		// last element
+		eMod_Last
+	};
+
+	typedef std::bitset<eMod_Last> Bitset;
+
 	TSubTaskContext& m_rSubTaskContext;
-	EOperationType m_eOperationType;
 
 #pragma warning(push)
 #pragma warning(disable: 4251)
+	mutable Bitset m_setModifications;
+
+	TSharedModificationTracker<EOperationType, Bitset, eMod_OperationType> m_eOperationType;
+
 	std::vector<std::pair<TSubTaskBasePtr, bool> > m_vSubTasks;	// pointer to the subtask object / is this the part of estimation?
 
 	mutable boost::atomic<long> m_lSubOperationIndex;		 // index of sub-operation from TOperationDescription
-	mutable long m_lLastStoredIndex;
 #pragma warning(pop)
 
+	mutable long m_lLastStoredIndex;
+
 	friend class TTaskProcessingGuard;
 };