diff options
| author | George Hazan <george.hazan@gmail.com> | 2012-10-03 18:27:17 +0000 | 
|---|---|---|
| committer | George Hazan <george.hazan@gmail.com> | 2012-10-03 18:27:17 +0000 | 
| commit | 8cb2a99e08a3f8fadc3b39f00228efa7d2b20050 (patch) | |
| tree | 65576462073546d462936d7ad8a2aa3e4e6147d8 | |
| parent | d2da1f079fc61195437007882296184714d2fe54 (diff) | |
database cache migration, phase 1
git-svn-id: http://svn.miranda-ng.org/main/trunk@1772 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
| -rw-r--r-- | include/m_db_int.h | 57 | ||||
| -rw-r--r-- | plugins/Db3x_mmap/src/dbcontacts.cpp | 81 | ||||
| -rw-r--r-- | plugins/Db3x_mmap/src/dbintf.cpp | 34 | ||||
| -rw-r--r-- | plugins/Db3x_mmap/src/dbintf.h | 47 | ||||
| -rw-r--r-- | plugins/Db3x_mmap/src/dbsettings.cpp | 189 | ||||
| -rw-r--r-- | plugins/Dbx_tree/DataBase.cpp | 9 | ||||
| -rw-r--r-- | src/miranda32_10.vcxproj | 4 | ||||
| -rw-r--r-- | src/miranda32_10.vcxproj.filters | 6 | ||||
| -rw-r--r-- | src/modules/database/database.h | 49 | ||||
| -rw-r--r-- | src/modules/database/dbintf.cpp | 22 | ||||
| -rw-r--r-- | src/modules/database/mdatabasecache.cpp | 233 | 
11 files changed, 425 insertions, 306 deletions
diff --git a/include/m_db_int.h b/include/m_db_int.h index df6671a486..cd498c5330 100644 --- a/include/m_db_int.h +++ b/include/m_db_int.h @@ -31,8 +31,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  ///////////////////////////////////////////////////////////////////////////////
  // basic database interface
 +struct DBCachedGlobalValue
 +{
 +	char* name;
 +	DBVARIANT value;
 +};
 +
 +struct DBCachedContactValue
 +{
 +	char* name;
 +	DBVARIANT value;
 +	DBCachedContactValue* next;
 +};
 +
 +struct DBCachedContact
 +{
 +	HANDLE hContact;
 +	HANDLE hNext;
 +	DBCachedContactValue* first;
 +	DBCachedContactValue* last;
 +};
 +
 +interface MIDatabaseCache
 +{
 +	STDMETHOD_(DBCachedContact*,AddContactToCache)(HANDLE hContact) PURE;
 +	STDMETHOD_(DBCachedContact*,GetCachedContact)(HANDLE hContact) PURE;
 +	STDMETHOD_(void,FreeCachedContact)(HANDLE hContact) PURE;
 +
 +	STDMETHOD_(char*,InsertCachedSetting)(const char *szName, int) PURE;
 +	STDMETHOD_(char*,GetCachedSetting)(const char *szModuleName, const char *szSettingName, int, int) PURE;
 +	STDMETHOD_(void,SetCachedVariant)(DBVARIANT *s, DBVARIANT *d) PURE;
 +	STDMETHOD_(DBVARIANT*,GetCachedValuePtr)(HANDLE hContact, char *szSetting, int bAllocate) PURE;
 +};
 +
  interface MIDatabase
  {
 +	MIDatabaseCache* m_cache;
 +
  	STDMETHOD_(void,SetCacheSafetyMode)(BOOL) PURE;
  	STDMETHOD_(LONG,GetContactCount)(void) PURE;
 @@ -194,4 +229,26 @@ __forceinline MIDatabase* GetCurrentDatabase(void)  {	return (MIDatabase*)CallService(MS_DB_GET_CURRENT, 0, 0);
  }
 +// MS_DB_INIT_INSTANCE : initializes a database instance
 +// wParam : 0 (unused)
 +// lParam : MIDatabase* = pointer to a database instance
 +// returns 0
 +
 +#define MS_DB_INIT_INSTANCE "DB/InitDbInstance"
 +
 +__forceinline void InitDbInstance(MIDatabase* pDatabase)
 +{	CallService(MS_DB_INIT_INSTANCE, 0, (LPARAM)pDatabase);
 +}
 +
 +// MS_DB_DESTROY_INSTANCE : destroys a database instance
 +// wParam : 0 (unused)
 +// lParam : MIDatabase* = pointer to a database instance
 +// returns 0
 +
 +#define MS_DB_DESTROY_INSTANCE "DB/DestroyDbInstance"
 +
 +__forceinline void DestroyDbInstance(MIDatabase* pDatabase)
 +{	CallService(MS_DB_DESTROY_INSTANCE, 0, (LPARAM)pDatabase);
 +}
 +
  #endif // M_DB_INT_H__
 diff --git a/plugins/Db3x_mmap/src/dbcontacts.cpp b/plugins/Db3x_mmap/src/dbcontacts.cpp index 7dcbdc6206..c8be49a189 100644 --- a/plugins/Db3x_mmap/src/dbcontacts.cpp +++ b/plugins/Db3x_mmap/src/dbcontacts.cpp @@ -23,34 +23,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  #include "commonheaders.h"
 -DBCachedContactValueList* CDb3Base::AddToCachedContactList(HANDLE hContact, int index)
 -{
 -	DBCachedContactValueList* VL = (DBCachedContactValueList*)HeapAlloc(m_hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
 -	VL->hContact = hContact;
 -	if (index == -1)
 -		m_lContacts.insert(VL);
 -	else
 -		m_lContacts.insert(VL,index);
 -	return VL;
 -}
 -
 -#define proto_module  "Protocol"
 -#define proto_setting "p"
 -
  int CDb3Base::CheckProto(HANDLE hContact, const char *proto)
  {
  	char protobuf[MAX_PATH] = {0};
  	DBVARIANT dbv;
 -	DBCONTACTGETSETTING sVal = {proto_module,proto_setting,&dbv};
 +	DBCONTACTGETSETTING sVal = { "Protocol", "p", &dbv };
   	dbv.type = DBVT_ASCIIZ;
  	dbv.pszVal = protobuf;
  	dbv.cchVal = sizeof(protobuf);
 -	if (GetContactSettingStatic(hContact, &sVal) != 0 || (dbv.type != DBVT_ASCIIZ))
 +	if ( GetContactSettingStatic(hContact, &sVal) != 0 || (dbv.type != DBVT_ASCIIZ))
  		return 0;
 -	return !strcmp(protobuf,proto);
 +	return !strcmp(protobuf, proto);
  }
  STDMETHODIMP_(LONG) CDb3Base::GetContactCount(void)
 @@ -70,34 +56,30 @@ STDMETHODIMP_(HANDLE) CDb3Base::FindFirstContact(const char *szProto)  STDMETHODIMP_(HANDLE) CDb3Base::FindNextContact(HANDLE hContact, const char *szProto)
  {
 -	DBCachedContactValueList VLtemp, *VL = NULL;
 -	VLtemp.hContact = hContact;
 -
  	mir_cslock lck(m_csDbAccess);
 -	while (VLtemp.hContact) {
 -		int index;
 -		if (( index = m_lContacts.getIndex(&VLtemp)) != -1) {
 -			VL = m_lContacts[index];
 +	while (hContact) {
 +		DBCachedContact *VL = m_cache->GetCachedContact(hContact);
 +		if (VL != NULL) {
  			if (VL->hNext != NULL) {
  				if (!szProto || CheckProto(VL->hNext, szProto))
  					return VL->hNext;
 -				VLtemp.hContact = VL->hNext;
 +				hContact = VL->hNext;
  				continue;
  		}	}
 -		DBContact *dbc = (DBContact*)DBRead(VLtemp.hContact,sizeof(DBContact),NULL);
 +		DBContact *dbc = (DBContact*)DBRead(hContact, sizeof(DBContact), NULL);
  		if (dbc->signature != DBCONTACT_SIGNATURE)
  			break;
 -		if ( VL == NULL )
 -			VL = AddToCachedContactList(VLtemp.hContact,index);
 +		if (VL == NULL)
 +			VL = m_cache->AddContactToCache(hContact);
  		VL->hNext = (HANDLE)dbc->ofsNext;
  		if (VL->hNext != NULL && (!szProto || CheckProto(VL->hNext, szProto)))
  			return VL->hNext;
 -		VLtemp.hContact = VL->hNext;
 +		hContact = VL->hNext;
  	}
  	return NULL;
 @@ -127,24 +109,9 @@ STDMETHODIMP_(LONG) CDb3Base::DeleteContact(HANDLE hContact)  	// get back in
  	lck.lock();
 -	DBCachedContactValueList VLtemp;
 -	VLtemp.hContact = hContact;
 -	int index;
 -	if ((index = m_lContacts.getIndex(&VLtemp)) != -1) {
 -		DBCachedContactValueList *VL = m_lContacts[index];
 -		DBCachedContactValue* V = VL->first;
 -		while ( V != NULL ) {
 -			DBCachedContactValue* V1 = V->next;
 -			FreeCachedVariant(&V->value);
 -			HeapFree( m_hCacheHeap, 0, V );
 -			V = V1;
 -		}
 -		HeapFree( m_hCacheHeap, 0, VL );
 -
 -		if (VLtemp.hContact == m_hLastCachedContact)
 -			m_hLastCachedContact = NULL;
 -		m_lContacts.remove(index);
 -	}
 +	m_cache->FreeCachedContact(hContact);
 +	if (hContact == m_hLastCachedContact)
 +		m_hLastCachedContact = NULL;
  	dbc = (DBContact*)DBRead(hContact, sizeof(DBContact), NULL);
  	//delete settings chain
 @@ -182,12 +149,9 @@ STDMETHODIMP_(LONG) CDb3Base::DeleteContact(HANDLE hContact)  		dbcPrev->ofsNext = ofsNext;
  		DBWrite(ofsThis,dbcPrev,sizeof(DBContact));
 -		DBCachedContactValueList VLtemp;
 -		VLtemp.hContact = (HANDLE)ofsThis;
 -		if ((index = m_lContacts.getIndex(&VLtemp)) != -1) {
 -			DBCachedContactValueList *VL = m_lContacts[index];
 +		DBCachedContact *VL = m_cache->GetCachedContact((HANDLE)ofsThis);
 +		if (VL)
  			VL->hNext = (HANDLE)ofsNext;
 -		}
  	}
  	//delete contact
 @@ -215,9 +179,8 @@ STDMETHODIMP_(HANDLE) CDb3Base::AddContact()  		DBWrite(ofsNew,&dbc,sizeof(DBContact));
  		DBWrite(0,&m_dbHeader,sizeof(m_dbHeader));
  		DBFlush(0);
 -
 -		AddToCachedContactList((HANDLE)ofsNew, -1);
  	}
 +	m_cache->AddContactToCache((HANDLE)ofsNew);
  	NotifyEventHooks(hContactAddedEvent,(WPARAM)ofsNew,0);
  	return (HANDLE)ofsNew;
 @@ -225,17 +188,13 @@ STDMETHODIMP_(HANDLE) CDb3Base::AddContact()  STDMETHODIMP_(BOOL) CDb3Base::IsDbContact(HANDLE hContact)
  {
 -	mir_cslock lck(m_csDbAccess);
 -
 -	DBCachedContactValueList VLtemp;
 -	VLtemp.hContact = hContact;
 -	int index = m_lContacts.getIndex(&VLtemp);
 -	if (index != -1)
 +	if (m_cache->GetCachedContact(hContact))
  		return TRUE;
 +	mir_cslock lck(m_csDbAccess);
  	DBContact *dbc = (DBContact*)DBRead(hContact,sizeof(DBContact),NULL);
  	if (dbc->signature == DBCONTACT_SIGNATURE) {
 -		AddToCachedContactList(hContact, index);
 +		m_cache->AddContactToCache(hContact);
  		return TRUE;
  	}
 diff --git a/plugins/Db3x_mmap/src/dbintf.cpp b/plugins/Db3x_mmap/src/dbintf.cpp index 34a34ab6ab..be56756d35 100644 --- a/plugins/Db3x_mmap/src/dbintf.cpp +++ b/plugins/Db3x_mmap/src/dbintf.cpp @@ -25,21 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  DBSignature dbSignature = {"Miranda ICQ DB",0x1A};
 -static int stringCompare(const char* p1, const char* p2)
 -{
 -	return strcmp(p1+1, p2+1);
 -}
 -
 -static int stringCompare2(const char* p1, const char* p2)
 -{
 -	return strcmp(p1, p2);
 -}
 -
 -static int compareGlobals(const DBCachedGlobalValue* p1, const DBCachedGlobalValue* p2)
 -{
 -	return strcmp(p1->name, p2->name);
 -}
 -
  static int ModCompare(const ModuleName *mn1, const ModuleName *mn2 )
  {
  	return strcmp( mn1->name, mn2->name );
 @@ -50,18 +35,20 @@ static int OfsCompare(const ModuleName *mn1, const ModuleName *mn2 )  	return ( mn1->ofs - mn2->ofs );
  }
 +static int stringCompare2(const char* p1, const char* p2)
 +{	return strcmp(p1, p2);
 +}
 +
  CDb3Base::CDb3Base(const TCHAR* tszFileName) :
  	m_hDbFile(INVALID_HANDLE_VALUE),
  	m_safetyMode(true),
  	m_bReadOnly(true),
 -	m_lSettings(100, stringCompare),
 -	m_lContacts(50, LIST<DBCachedContactValueList>::FTSortFunc(HandleKeySort)),
 -	m_lGlobalSettings(50, compareGlobals),
 -	m_lResidentSettings(50, stringCompare2),
  	m_lMods(50, ModCompare),
 -	m_lOfs(50, OfsCompare)
 +	m_lOfs(50, OfsCompare),
 +	m_lResidentSettings(50, stringCompare2)
  {
  	m_tszProfileName = mir_tstrdup(tszFileName);
 +	InitDbInstance(this);
  	InitializeCriticalSection(&m_csDbAccess);
 @@ -70,17 +57,11 @@ CDb3Base::CDb3Base(const TCHAR* tszFileName) :  	m_ChunkSize = sinf.dwAllocationGranularity;
  	m_codePage = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0);
 -	m_hCacheHeap = HeapCreate(0, 0, 0);
  	m_hModHeap = HeapCreate(0,0,0);
  }
  CDb3Base::~CDb3Base()
  {
 -	// destroy settings
 -	HeapDestroy(m_hCacheHeap);
 -	m_lContacts.destroy();
 -	m_lSettings.destroy();
 -	m_lGlobalSettings.destroy();
  	m_lResidentSettings.destroy();
  	// destroy modules
 @@ -108,6 +89,7 @@ CDb3Base::~CDb3Base()  	DeleteCriticalSection(&m_csDbAccess);
 +	DestroyDbInstance(this);
  	mir_free(m_tszProfileName);
  }
 diff --git a/plugins/Db3x_mmap/src/dbintf.h b/plugins/Db3x_mmap/src/dbintf.h index d5bef059ef..a810b36876 100644 --- a/plugins/Db3x_mmap/src/dbintf.h +++ b/plugins/Db3x_mmap/src/dbintf.h @@ -136,27 +136,6 @@ struct DBEvent  #include <poppack.h>
 -struct DBCachedGlobalValue
 -{
 -	char* name;
 -	DBVARIANT value;
 -};
 -
 -struct DBCachedContactValue
 -{
 -	char* name;
 -	DBVARIANT value;
 -	DBCachedContactValue* next;
 -};
 -
 -struct DBCachedContactValueList
 -{
 -	HANDLE hContact;
 -	HANDLE hNext;
 -	DBCachedContactValue* first;
 -	DBCachedContactValue* last;
 -};
 -
  #define MAXCACHEDREADSIZE     65536
  struct CDb3Base : public MIDatabase, public MIDatabaseChecker, public MZeroedObject
 @@ -255,6 +234,7 @@ public:  protected:
  	DWORD    m_dwFileSize;
 +	HANDLE   hSettingChangeEvent, hContactDeletedEvent, hContactAddedEvent;
  	CRITICAL_SECTION m_csDbAccess;
 @@ -272,34 +252,14 @@ protected:  	int m_codePage;
 -	HANDLE m_hCacheHeap;
 -	HANDLE m_hLastCachedContact;
 -	char* m_lastSetting;
 -	DBCachedContactValueList *m_lastVL;
 -
 -	LIST<DBCachedContactValueList> m_lContacts;
 -	LIST<DBCachedGlobalValue> m_lGlobalSettings;
 -	LIST<char> m_lSettings, m_lResidentSettings;
 -	HANDLE hSettingChangeEvent, hContactDeletedEvent, hContactAddedEvent;
 -
 -	char* InsertCachedSetting(const char* szName, size_t cbNameLen);
 -	char* GetCachedSetting(const char *szModuleName,const char *szSettingName, int moduleNameLen, int settingNameLen);
 -	void SetCachedVariant(DBVARIANT* s, DBVARIANT* d);
 -	void FreeCachedVariant(DBVARIANT* V);
 -	DBVARIANT* GetCachedValuePtr(HANDLE hContact, char* szSetting, int bAllocate);
 -	int GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs,int isStatic);
 -
 -	////////////////////////////////////////////////////////////////////////////
 -	// contacts
 -
 -	DBCachedContactValueList* AddToCachedContactList(HANDLE hContact, int index);
 -
  	////////////////////////////////////////////////////////////////////////////
  	// modules
  	HANDLE m_hModHeap;
  	LIST<ModuleName> m_lMods, m_lOfs;
 +	LIST<char> m_lResidentSettings;
  	HANDLE hEventAddedEvent, hEventDeletedEvent, hEventFilterAddedEvent;
 +	HANDLE m_hLastCachedContact;
  	ModuleName *m_lastmn;
  	void  AddToList(char *name, DWORD len, DWORD ofs);
 @@ -320,6 +280,7 @@ protected:  	DWORD ConvertModuleNameOfs(DWORD ofsOld);
  	void ConvertOldEvent(DBEvent*& dbei);
 +	int GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs,int isStatic);
  	int WorkSettingsChain(DWORD ofsContact, DBContact *dbc, int firstTime);
  	int WorkEventChain(DWORD ofsContact, DBContact *dbc, int firstTime);
 diff --git a/plugins/Db3x_mmap/src/dbsettings.cpp b/plugins/Db3x_mmap/src/dbsettings.cpp index fedc5f60d2..872d482e27 100644 --- a/plugins/Db3x_mmap/src/dbsettings.cpp +++ b/plugins/Db3x_mmap/src/dbsettings.cpp @@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  #include "commonheaders.h"
  DWORD GetModuleNameOfs(const char *szName);
 -DBCachedContactValueList* AddToCachedContactList(HANDLE hContact, int index);
 +DBCachedContact* AddToCachedContactList(HANDLE hContact, int index);
  int DBPreset_QuerySetting(const char *szModule, const char *szSetting, DBVARIANT *dbv, BOOL isStatic);
 @@ -35,154 +35,6 @@ DWORD __forceinline GetSettingValueLength(PBYTE pSetting)  	return pSetting[0];
  }
 -char* CDb3Base::InsertCachedSetting(const char* szName, size_t cbNameLen)
 -{
 -	char* newValue = (char*)HeapAlloc(m_hCacheHeap, 0, cbNameLen);
 -	*newValue = 0;
 -	strcpy(newValue+1, szName+1);
 -	m_lSettings.insert(newValue);
 -	return newValue;
 -}
 -
 -char* CDb3Base::GetCachedSetting(const char *szModuleName,const char *szSettingName, int moduleNameLen, int settingNameLen)
 -{
 -	char szFullName[512];
 -	strcpy(szFullName+1,szModuleName);
 -	szFullName[moduleNameLen+1] = '/';
 -	strcpy(szFullName+moduleNameLen+2,szSettingName);
 -
 -	if (m_lastSetting && strcmp(szFullName+1, m_lastSetting) == 0)
 -		return m_lastSetting;
 -
 -	int index = m_lSettings.getIndex(szFullName);
 -	if (index != -1)
 -		m_lastSetting = m_lSettings[index]+1;
 -	else
 -		m_lastSetting = InsertCachedSetting( szFullName, settingNameLen+moduleNameLen+3)+1;
 -
 -	return m_lastSetting;
 -}
 -
 -void CDb3Base::SetCachedVariant( DBVARIANT* s /* new */, DBVARIANT* d /* cached */ )
 -{
 -	char* szSave = ( d->type == DBVT_UTF8 || d->type == DBVT_ASCIIZ ) ? d->pszVal : NULL;
 -
 -	memcpy( d, s, sizeof( DBVARIANT ));
 -	if (( s->type == DBVT_UTF8 || s->type == DBVT_ASCIIZ ) && s->pszVal != NULL ) {
 -		if ( szSave != NULL )
 -			d->pszVal = (char*)HeapReAlloc(m_hCacheHeap,0,szSave,strlen(s->pszVal)+1);
 -		else
 -			d->pszVal = (char*)HeapAlloc(m_hCacheHeap,0,strlen(s->pszVal)+1);
 -		strcpy(d->pszVal,s->pszVal);
 -	}
 -	else if ( szSave != NULL )
 -		HeapFree(m_hCacheHeap,0,szSave);
 -
 -#ifdef DBLOGGING
 -	switch( d->type ) {
 -		case DBVT_BYTE:	log1( "set cached byte: %d", d->bVal ); break;
 -		case DBVT_WORD:	log1( "set cached word: %d", d->wVal ); break;
 -		case DBVT_DWORD:	log1( "set cached dword: %d", d->dVal ); break;
 -		case DBVT_UTF8:
 -		case DBVT_ASCIIZ: log1( "set cached string: '%s'", d->pszVal ); break;
 -		default:				log1( "set cached crap: %d", d->type ); break;
 -	}
 -#endif
 -}
 -
 -void CDb3Base::FreeCachedVariant( DBVARIANT* V )
 -{
 -	if (( V->type == DBVT_ASCIIZ || V->type == DBVT_UTF8 ) && V->pszVal != NULL )
 -		HeapFree(m_hCacheHeap,0,V->pszVal);
 -}
 -
 -DBVARIANT* CDb3Base::GetCachedValuePtr( HANDLE hContact, char* szSetting, int bAllocate )
 -{
 -	if ( hContact == 0 ) {
 -		DBCachedGlobalValue Vtemp, *V;
 -		Vtemp.name = szSetting;
 -		int index = m_lGlobalSettings.getIndex(&Vtemp);
 -		if (index != -1) {
 -			V = m_lGlobalSettings[index];
 -			if ( bAllocate == -1 ) {
 -				FreeCachedVariant( &V->value );
 -				m_lGlobalSettings.remove(index);
 -				HeapFree(m_hCacheHeap,0,V);
 -				return NULL;
 -			}
 -		}
 -		else {
 -			if ( bAllocate != 1 )
 -				return NULL;
 -
 -			V = (DBCachedGlobalValue*)HeapAlloc(m_hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedGlobalValue));
 -			V->name = szSetting;
 -			m_lGlobalSettings.insert(V);
 -		}
 -
 -		return &V->value;
 -	}
 -	else {
 -		DBCachedContactValue *V, *V1;
 -		DBCachedContactValueList VLtemp,*VL;
 -
 -		if (m_hLastCachedContact == hContact && m_lastVL)
 -			VL = m_lastVL;
 -		else {
 -			VLtemp.hContact = hContact;
 -
 -			int index = m_lContacts.getIndex(&VLtemp);
 -			if (index == -1) {
 -				if ( bAllocate != 1 )
 -					return NULL;
 -
 -				VL = AddToCachedContactList(hContact, index);
 -			}
 -			else VL = m_lContacts[index];
 -
 -			m_lastVL = VL;
 -			m_hLastCachedContact = hContact;
 -		}
 -
 -		for ( V = VL->first; V != NULL; V = V->next)
 -			if (V->name == szSetting)
 -				break;
 -
 -		if ( V == NULL ) {
 -			if ( bAllocate != 1 )
 -				return NULL;
 -
 -			V = (DBCachedContactValue *)HeapAlloc(m_hCacheHeap, HEAP_ZERO_MEMORY, sizeof(DBCachedContactValue));
 -			if (VL->last)
 -				VL->last->next = V;
 -			else
 -				VL->first = V;
 -			VL->last = V;
 -			V->name = szSetting;
 -		}
 -		else if ( bAllocate == -1 ) {
 -		   m_lastVL = NULL;
 -			FreeCachedVariant(&V->value);
 -			if ( VL->first == V ) {
 -				VL->first = V->next;
 -				if (VL->last == V)
 -					VL->last = V->next; // NULL
 -			}
 -			else
 -				for ( V1 = VL->first; V1 != NULL; V1 = V1->next )
 -					if ( V1->next == V ) {
 -						V1->next = V->next;
 -						if (VL->last == V)
 -							VL->last = V1;
 -						break;
 -					}
 -			HeapFree(m_hCacheHeap,0,V);
 -			return NULL;
 -		}
 -
 -		return &V->value;
 -}	}
 -
  #define NeedBytes(n)   if (bytesRemaining<(n)) pBlob = (PBYTE)DBRead(ofsBlobPtr,(n),&bytesRemaining)
  #define MoveAlong(n)   {int x = n; pBlob += (x); ofsBlobPtr += (x); bytesRemaining -= (x);}
  #define VLT(n) ((n == DBVT_UTF8)?DBVT_ASCIIZ:n)
 @@ -219,9 +71,9 @@ int CDb3Base::GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs  	log3("get [%08p] %s/%s",hContact,dbcgs->szModule,dbcgs->szSetting);
 -	szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,moduleNameLen,settingNameLen);
 +	szCachedSettingName = m_cache->GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,moduleNameLen,settingNameLen);
  	{
 -		DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 0 );
 +		DBVARIANT* pCachedValue = m_cache->GetCachedValuePtr(hContact, szCachedSettingName, 0);
  		if ( pCachedValue != NULL ) {
  			if ( pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8 ) {
  				int   cbOrigLen = dbcgs->pValue->cchVal;
 @@ -320,9 +172,9 @@ int CDb3Base::GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs  				/**** add to cache **********************/
  				if ( dbcgs->pValue->type != DBVT_BLOB ) {
 -					DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
 +					DBVARIANT* pCachedValue = m_cache->GetCachedValuePtr( hContact, szCachedSettingName, 1 );
  					if ( pCachedValue != NULL )
 -						SetCachedVariant(dbcgs->pValue,pCachedValue);
 +						m_cache->SetCachedVariant(dbcgs->pValue, pCachedValue);
  				}
  				logg();
 @@ -351,7 +203,7 @@ int CDb3Base::GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs  	/**** add missing setting to cache **********************/
  	if ( dbcgs->pValue->type != DBVT_BLOB )
  	{
 -		DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
 +		DBVARIANT* pCachedValue = m_cache->GetCachedValuePtr( hContact, szCachedSettingName, 1 );
  		if ( pCachedValue != NULL )
  			pCachedValue->type = DBVT_DELETED;
  	}
 @@ -479,22 +331,13 @@ STDMETHODIMP_(BOOL) CDb3Base::FreeVariant(DBVARIANT *dbv)  STDMETHODIMP_(BOOL) CDb3Base::SetSettingResident(BOOL bIsResident, const char *pszSettingName)
  {
 -	size_t cbSettingNameLen = strlen(pszSettingName) + 2;
 +	int cbSettingNameLen = (int)strlen(pszSettingName) + 2;
  	if (cbSettingNameLen < 512) {
 -		char*  szSetting;
 -		char  szTemp[512];
 -		strcpy( szTemp+1, pszSettingName);
 -
 -		mir_cslock lck(m_csDbAccess);
 -		int idx = m_lSettings.getIndex(szTemp);
 -		if (idx == -1)
 -			szSetting = InsertCachedSetting( szTemp, cbSettingNameLen);
 -		else
 -			szSetting = m_lSettings[idx];
 -
 +		char *szSetting = m_cache->InsertCachedSetting(pszSettingName, cbSettingNameLen);
  		*szSetting = (char)bIsResident;
 -		idx = m_lResidentSettings.getIndex(szSetting+1);
 +		mir_cslock lck(m_csDbAccess);
 +		int idx = m_lResidentSettings.getIndex(szSetting+1);
  		if (idx == -1) {
  			if (bIsResident)
  				m_lResidentSettings.insert(szSetting+1);
 @@ -574,9 +417,9 @@ STDMETHODIMP_(BOOL) CDb3Base::WriteContactSetting(HANDLE hContact, DBCONTACTWRIT  	mir_cslockfull lck(m_csDbAccess);
 -	char* szCachedSettingName = GetCachedSetting(tmp.szModule, tmp.szSetting, moduleNameLen, settingNameLen);
 +	char* szCachedSettingName = m_cache->GetCachedSetting(tmp.szModule, tmp.szSetting, moduleNameLen, settingNameLen);
  	if ( tmp.value.type != DBVT_BLOB ) {
 -		DBVARIANT* pCachedValue = GetCachedValuePtr(hContact, szCachedSettingName, 1);
 +		DBVARIANT* pCachedValue = m_cache->GetCachedValuePtr(hContact, szCachedSettingName, 1);
  		if ( pCachedValue != NULL ) {
  			BOOL bIsIdentical = FALSE;
  			if ( pCachedValue->type == tmp.value.type ) {
 @@ -590,7 +433,7 @@ STDMETHODIMP_(BOOL) CDb3Base::WriteContactSetting(HANDLE hContact, DBCONTACTWRIT  				if ( bIsIdentical )
  					return 0;
  			}
 -			SetCachedVariant(&tmp.value, pCachedValue);
 +			m_cache->SetCachedVariant(&tmp.value, pCachedValue);
  		}
  		if ( szCachedSettingName[-1] != 0 ) {
  			lck.unlock();
 @@ -598,7 +441,7 @@ STDMETHODIMP_(BOOL) CDb3Base::WriteContactSetting(HANDLE hContact, DBCONTACTWRIT  			return 0;
  		}
  	}
 -	else GetCachedValuePtr(hContact, szCachedSettingName, -1);
 +	else m_cache->GetCachedValuePtr(hContact, szCachedSettingName, -1);
  	ofsModuleName = GetModuleNameOfs(tmp.szModule);
   	if (hContact == 0) ofsContact = m_dbHeader.ofsUser;
 @@ -851,8 +694,8 @@ STDMETHODIMP_(BOOL) CDb3Base::DeleteContactSetting(HANDLE hContact, DBCONTACTGET  	}
  	DBMoveChunk(ofsSettingToCut,ofsSettingToCut+nameLen+valLen,ofsBlobPtr+1-ofsSettingToCut);
 -	szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,moduleNameLen,settingNameLen);
 -	GetCachedValuePtr((HANDLE)saveWparam, szCachedSettingName, -1 );
 +	szCachedSettingName = m_cache->GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,moduleNameLen,settingNameLen);
 +	m_cache->GetCachedValuePtr((HANDLE)saveWparam, szCachedSettingName, -1 );
  	//quit
  	DBFlush(1);
 diff --git a/plugins/Dbx_tree/DataBase.cpp b/plugins/Dbx_tree/DataBase.cpp index 033e472c9d..50fe494b3c 100644 --- a/plugins/Dbx_tree/DataBase.cpp +++ b/plugins/Dbx_tree/DataBase.cpp @@ -31,12 +31,13 @@ CDataBase *gDataBase = NULL;  CDataBase::CDataBase(const TCHAR *FileName)
  {
 -	int len = _tcslen(FileName);
 +	InitDbInstance(this);
 +
 +	size_t len = _tcslen(FileName);
  	m_FileName[0] = new TCHAR[len + 1];
  	_tcsncpy_s(m_FileName[0], len + 1, FileName, len);
  	m_FileName[0][len] = 0;
 -
  	TCHAR * tmp = _tcsrchr(m_FileName[0], '.');
  	if (tmp)
  	{
 @@ -62,6 +63,7 @@ CDataBase::CDataBase(const TCHAR *FileName)  	m_Entities = NULL;
  	m_Settings = NULL;
  	m_Events   = NULL;
 +
  }
  CDataBase::~CDataBase()
  {
 @@ -85,8 +87,9 @@ CDataBase::~CDataBase()  		delete [] (m_FileName[i]);
  	}
 -
 +	DestroyDbInstance(this);
  }
 +
  int CDataBase::CreateDB()
  {
  	/// TODO: create and show wizard
 diff --git a/src/miranda32_10.vcxproj b/src/miranda32_10.vcxproj index ca0f8ffa35..5707d30e91 100644 --- a/src/miranda32_10.vcxproj +++ b/src/miranda32_10.vcxproj @@ -244,6 +244,7 @@      <ClInclude Include="core\commonheaders.h" />
      <ClInclude Include="core\miranda.h" />
      <ClInclude Include="core\stdplug.h" />
 +    <ClInclude Include="modules\database\database.h" />
      <ClInclude Include="modules\database\profilemanager.h" />
      <ClInclude Include="modules\findadd\findadd.h" />
      <ClInclude Include="modules\json\internalJSONNode.h" />
 @@ -299,6 +300,9 @@      <ClCompile Include="modules\database\dbutils.cpp">
        <PrecompiledHeaderFile>..\..\core\commonheaders.h</PrecompiledHeaderFile>
      </ClCompile>
 +    <ClCompile Include="modules\database\mdatabasecache.cpp">
 +      <PrecompiledHeaderFile>..\..\core\commonheaders.h</PrecompiledHeaderFile>
 +    </ClCompile>
      <ClCompile Include="modules\database\profilemanager.cpp">
        <PrecompiledHeaderFile>..\..\core\commonheaders.h</PrecompiledHeaderFile>
      </ClCompile>
 diff --git a/src/miranda32_10.vcxproj.filters b/src/miranda32_10.vcxproj.filters index dd95088c4f..fb7f03cd6e 100644 --- a/src/miranda32_10.vcxproj.filters +++ b/src/miranda32_10.vcxproj.filters @@ -270,6 +270,9 @@      <ClInclude Include="..\include\m_db_int.h">
        <Filter>Modules\database</Filter>
      </ClInclude>
 +    <ClInclude Include="modules\database\database.h">
 +      <Filter>Modules\database</Filter>
 +    </ClInclude>
    </ItemGroup>
    <ItemGroup>
      <ClCompile Include="core\commonheaders.cpp">
 @@ -572,6 +575,9 @@      <ClCompile Include="modules\clist\contacts.cpp">
        <Filter>Modules\clist</Filter>
      </ClCompile>
 +    <ClCompile Include="modules\database\mdatabasecache.cpp">
 +      <Filter>Modules\database</Filter>
 +    </ClCompile>
    </ItemGroup>
    <ItemGroup>
      <ResourceCompile Include="resource.rc">
 diff --git a/src/modules/database/database.h b/src/modules/database/database.h new file mode 100644 index 0000000000..b0b5717e0b --- /dev/null +++ b/src/modules/database/database.h @@ -0,0 +1,49 @@ +/*
 +
 +Miranda NG: the free IM client for Microsoft* Windows*
 +
 +Copyright 2012 Miranda NG project,
 +all portions of this codebase are copyrighted to the people
 +listed in contributors.txt.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program; if not, write to the Free Software
 +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 +*/
 +
 +class MDatabaseCache : public MIDatabaseCache, public MZeroedObject
 +{
 +	HANDLE m_hCacheHeap;
 +	char* m_lastSetting;
 +	DBCachedContact *m_lastVL;
 +
 +	LIST<DBCachedContact> m_lContacts;
 +	LIST<DBCachedGlobalValue> m_lGlobalSettings;
 +	LIST<char> m_lSettings;
 +
 +	void FreeCachedVariant(DBVARIANT* V);
 +
 +public:
 +	MDatabaseCache();
 +	~MDatabaseCache();
 +
 +protected:
 +	STDMETHODIMP_(DBCachedContact*) AddContactToCache(HANDLE hContact);
 +	STDMETHODIMP_(DBCachedContact*) GetCachedContact(HANDLE hContact);
 +	STDMETHODIMP_(void) FreeCachedContact(HANDLE hContact);
 +
 +	STDMETHODIMP_(char*) InsertCachedSetting(const char *szName, int);
 +	STDMETHODIMP_(char*) GetCachedSetting(const char *szModuleName, const char *szSettingName, int, int);
 +	STDMETHODIMP_(void)  SetCachedVariant(DBVARIANT *s, DBVARIANT *d);
 +	STDMETHODIMP_(DBVARIANT*) GetCachedValuePtr(HANDLE hContact, char *szSetting, int bAllocate);
 +};
 diff --git a/src/modules/database/dbintf.cpp b/src/modules/database/dbintf.cpp index 6c6371e6ec..da83e284d2 100644 --- a/src/modules/database/dbintf.cpp +++ b/src/modules/database/dbintf.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
  #include "..\..\core\commonheaders.h"
 +#include "database.h"
  MIDatabase *currDb = NULL;
  DATABASELINK *currDblink = NULL;
 @@ -191,6 +192,24 @@ static INT_PTR srvGetCurrentDb(WPARAM wParam,LPARAM lParam)  	return (INT_PTR)currDb;
  }
 +static INT_PTR srvInitInstance(WPARAM wParam,LPARAM lParam)
 +{
 +	MIDatabase* pDb = (MIDatabase*)lParam;
 +	if (pDb != NULL)
 +		pDb->m_cache = new MDatabaseCache();
 +	return 0;
 +}
 +
 +static INT_PTR srvDestroyInstance(WPARAM wParam,LPARAM lParam)
 +{
 +	MIDatabase* pDb = (MIDatabase*)lParam;
 +	if (pDb != NULL) {
 +		delete pDb->m_cache;
 +		pDb->m_cache = NULL;
 +	}
 +	return 0;
 +}
 +
  ///////////////////////////////////////////////////////////////////////////////
  int LoadDbintfModule()
 @@ -232,5 +251,8 @@ int LoadDbintfModule()  	CreateServiceFunction(MS_DB_REGISTER_PLUGIN, srvRegisterPlugin);
  	CreateServiceFunction(MS_DB_FIND_PLUGIN, srvFindPlugin);
  	CreateServiceFunction(MS_DB_GET_CURRENT, srvGetCurrentDb);
 +
 +	CreateServiceFunction(MS_DB_INIT_INSTANCE, srvInitInstance);
 +	CreateServiceFunction(MS_DB_DESTROY_INSTANCE, srvDestroyInstance);
  	return 0;
  }
 diff --git a/src/modules/database/mdatabasecache.cpp b/src/modules/database/mdatabasecache.cpp new file mode 100644 index 0000000000..abb24dd0fe --- /dev/null +++ b/src/modules/database/mdatabasecache.cpp @@ -0,0 +1,233 @@ +/*
 +
 +Miranda IM: the free IM client for Microsoft* Windows*
 +
 +Copyright 2000-2010 Miranda ICQ/IM project,
 +all portions of this codebase are copyrighted to the people
 +listed in contributors.txt.
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program; if not, write to the Free Software
 +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 +*/
 +
 +#include "..\..\core\commonheaders.h"
 +#include "database.h"
 +
 +static int stringCompare(const char* p1, const char* p2)
 +{	return strcmp(p1+1, p2+1);
 +}
 +
 +static int compareGlobals(const DBCachedGlobalValue* p1, const DBCachedGlobalValue* p2)
 +{	return strcmp(p1->name, p2->name);
 +}
 +
 +MDatabaseCache::MDatabaseCache() :
 +	m_lSettings(100, stringCompare),
 +	m_lContacts(50, LIST<DBCachedContact>::FTSortFunc(HandleKeySort)),
 +	m_lGlobalSettings(50, compareGlobals)
 +{
 +	m_hCacheHeap = HeapCreate(0, 0, 0);
 +}
 +
 +MDatabaseCache::~MDatabaseCache()
 +{
 +	HeapDestroy(m_hCacheHeap);
 +	m_lContacts.destroy();
 +	m_lSettings.destroy();
 +	m_lGlobalSettings.destroy();
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +DBCachedContact* MDatabaseCache::AddContactToCache(HANDLE hContact)
 +{
 +	DBCachedContact* VL = (DBCachedContact*)HeapAlloc(m_hCacheHeap, HEAP_ZERO_MEMORY, sizeof(DBCachedContact));
 +	VL->hContact = hContact;
 +	m_lContacts.insert(VL);
 +	return VL;
 +}
 +
 +DBCachedContact* MDatabaseCache::GetCachedContact(HANDLE hContact)
 +{
 +	DBCachedContact VLtemp = { hContact };
 +	int index = m_lContacts.getIndex(&VLtemp);
 +	return (index == -1) ? NULL : m_lContacts[index];
 +}
 +
 +void MDatabaseCache::FreeCachedContact(HANDLE hContact)
 +{
 +	DBCachedContact VLtemp = { hContact };
 +	int index = m_lContacts.getIndex(&VLtemp);
 +	if (index == -1)
 +		return;
 +
 +	DBCachedContact* VL = m_lContacts[index];
 +	DBCachedContactValue* V = VL->first;
 +	while (V != NULL) {
 +		DBCachedContactValue* V1 = V->next;
 +		FreeCachedVariant(&V->value);
 +		HeapFree( m_hCacheHeap, 0, V );
 +		V = V1;
 +	}
 +	HeapFree( m_hCacheHeap, 0, VL );
 +
 +	m_lContacts.remove(index);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////////////////
 +
 +char* MDatabaseCache::InsertCachedSetting(const char* szName, int cbLen)
 +{
 +	char* newValue = (char*)HeapAlloc(m_hCacheHeap, 0, cbLen);
 +	*newValue = 0;
 +	strcpy(newValue+1, szName+1);
 +	m_lSettings.insert(newValue);
 +	return newValue;
 +}
 +
 +char* MDatabaseCache::GetCachedSetting(const char *szModuleName,const char *szSettingName, int moduleNameLen, int settingNameLen)
 +{
 +	char szFullName[512];
 +	strcpy(szFullName+1,szModuleName);
 +	szFullName[moduleNameLen+1] = '/';
 +	strcpy(szFullName+moduleNameLen+2,szSettingName);
 +
 +	if (m_lastSetting && strcmp(szFullName+1, m_lastSetting) == 0)
 +		return m_lastSetting;
 +
 +	int index = m_lSettings.getIndex(szFullName);
 +	if (index != -1)
 +		m_lastSetting = m_lSettings[index]+1;
 +	else
 +		m_lastSetting = InsertCachedSetting( szFullName, settingNameLen+moduleNameLen+3)+1;
 +
 +	return m_lastSetting;
 +}
 +
 +void MDatabaseCache::SetCachedVariant(DBVARIANT* s /* new */, DBVARIANT* d /* cached */ )
 +{
 +	char* szSave = ( d->type == DBVT_UTF8 || d->type == DBVT_ASCIIZ ) ? d->pszVal : NULL;
 +
 +	memcpy( d, s, sizeof( DBVARIANT ));
 +	if (( s->type == DBVT_UTF8 || s->type == DBVT_ASCIIZ ) && s->pszVal != NULL ) {
 +		if ( szSave != NULL )
 +			d->pszVal = (char*)HeapReAlloc(m_hCacheHeap,0,szSave,strlen(s->pszVal)+1);
 +		else
 +			d->pszVal = (char*)HeapAlloc(m_hCacheHeap,0,strlen(s->pszVal)+1);
 +		strcpy(d->pszVal,s->pszVal);
 +	}
 +	else if ( szSave != NULL )
 +		HeapFree(m_hCacheHeap,0,szSave);
 +
 +#ifdef DBLOGGING
 +	switch( d->type ) {
 +		case DBVT_BYTE:	log1( "set cached byte: %d", d->bVal ); break;
 +		case DBVT_WORD:	log1( "set cached word: %d", d->wVal ); break;
 +		case DBVT_DWORD:	log1( "set cached dword: %d", d->dVal ); break;
 +		case DBVT_UTF8:
 +		case DBVT_ASCIIZ: log1( "set cached string: '%s'", d->pszVal ); break;
 +		default:				log1( "set cached crap: %d", d->type ); break;
 +	}
 +#endif
 +}
 +
 +void MDatabaseCache::FreeCachedVariant(DBVARIANT* V)
 +{
 +	if (( V->type == DBVT_ASCIIZ || V->type == DBVT_UTF8 ) && V->pszVal != NULL )
 +		HeapFree(m_hCacheHeap,0,V->pszVal);
 +}
 +
 +STDMETHODIMP_(DBVARIANT*) MDatabaseCache::GetCachedValuePtr(HANDLE hContact, char *szSetting, int bAllocate)
 +{
 +	// a global setting
 +	if ( hContact == 0 ) {
 +		DBCachedGlobalValue Vtemp, *V;
 +		Vtemp.name = szSetting;
 +		int index = m_lGlobalSettings.getIndex(&Vtemp);
 +		if (index != -1) {
 +			V = m_lGlobalSettings[index];
 +			if ( bAllocate == -1 ) {
 +				FreeCachedVariant( &V->value );
 +				m_lGlobalSettings.remove(index);
 +				HeapFree(m_hCacheHeap,0,V);
 +				return NULL;
 +			}
 +		}
 +		else {
 +			if ( bAllocate != 1 )
 +				return NULL;
 +
 +			V = (DBCachedGlobalValue*)HeapAlloc(m_hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedGlobalValue));
 +			V->name = szSetting;
 +			m_lGlobalSettings.insert(V);
 +		}
 +
 +		return &V->value;
 +	}
 +
 +	// a contact setting
 +	DBCachedContactValue *V, *V1;
 +	DBCachedContact VLtemp,*VL;
 +
 +	VLtemp.hContact = hContact;
 +
 +	int index = m_lContacts.getIndex(&VLtemp);
 +	if (index == -1) {
 +		if ( bAllocate != 1 )
 +			return NULL;
 +
 +		VL = AddContactToCache(hContact);
 +	}
 +	else VL = m_lContacts[index];
 +
 +	m_lastVL = VL;
 +
 +	for ( V = VL->first; V != NULL; V = V->next)
 +		if (V->name == szSetting)
 +			break;
 +
 +	if ( V == NULL ) {
 +		if ( bAllocate != 1 )
 +			return NULL;
 +
 +		V = (DBCachedContactValue *)HeapAlloc(m_hCacheHeap, HEAP_ZERO_MEMORY, sizeof(DBCachedContactValue));
 +		if (VL->last)
 +			VL->last->next = V;
 +		else
 +			VL->first = V;
 +		VL->last = V;
 +		V->name = szSetting;
 +	}
 +	else if ( bAllocate == -1 ) {
 +		m_lastVL = NULL;
 +		FreeCachedVariant(&V->value);
 +		if ( VL->first == V ) {
 +			VL->first = V->next;
 +			if (VL->last == V)
 +				VL->last = V->next; // NULL
 +		}
 +		else
 +			for ( V1 = VL->first; V1 != NULL; V1 = V1->next )
 +				if ( V1->next == V ) {
 +					V1->next = V->next;
 +					if (VL->last == V)
 +						VL->last = V1;
 +					break;
 +				}
 +		HeapFree(m_hCacheHeap,0,V);
 +		return NULL;
 +	}
 +
 +	return &V->value;
 +}
  | 
