ECCacheManager.cpp 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <mutex>
  19. #include <stdexcept>
  20. #include <utility>
  21. #include <mapidefs.h>
  22. #include <mapitags.h>
  23. #include <kopano/lockhelper.hpp>
  24. #include "ECDatabase.h"
  25. #include "ECSessionManager.h"
  26. #include "ECDatabaseUtils.h"
  27. #include "ECCacheManager.h"
  28. #include "ECMAPI.h"
  29. #include <kopano/stringutil.h>
  30. #include "ECGenericObjectTable.h"
  31. #include <algorithm>
  32. namespace KC {
  33. #define LOG_CACHE_DEBUG(_msg, ...) \
  34. ec_log(EC_LOGLEVEL_DEBUG | EC_LOGLEVEL_CACHE, "cache: " _msg, ##__VA_ARGS__)
  35. #define LOG_USERCACHE_DEBUG(_msg, ...) \
  36. ec_log(EC_LOGLEVEL_DEBUG | EC_LOGLEVEL_USERCACHE, "usercache: " _msg, ##__VA_ARGS__)
  37. #define LOG_CELLCACHE_DEBUG(_msg, ...) \
  38. ec_log(EC_LOGLEVEL_DEBUG | EC_LOGLEVEL_CACHE, "cellcache: " _msg, ##__VA_ARGS__)
  39. // Specialization for ECsACL
  40. template<>
  41. unsigned int GetCacheAdditionalSize(const ECsACLs &val) {
  42. return val.ulACLs * sizeof(val.aACL[0]);
  43. }
  44. template<>
  45. unsigned int GetCacheAdditionalSize(const ECsIndexProp &val) {
  46. return val.cbData;
  47. }
  48. // Specialization for ECsCell
  49. template<>
  50. unsigned int GetCacheAdditionalSize(const ECsCells &val) {
  51. return val.GetSize();
  52. }
  53. template<>
  54. unsigned int GetCacheAdditionalSize(const std::string &val) {
  55. return MEMORY_USAGE_STRING(val);
  56. }
  57. template<>
  58. unsigned int GetCacheAdditionalSize(const ECsUEIdKey &val) {
  59. return MEMORY_USAGE_STRING(val.strExternId);
  60. }
  61. ECCacheManager::ECCacheManager(ECConfig *lpConfig,
  62. ECDatabaseFactory *lpDatabaseFactory) :
  63. m_lpDatabaseFactory(lpDatabaseFactory),
  64. m_QuotaCache("quota", atoi(lpConfig->GetSetting("cache_quota_size")), atoi(lpConfig->GetSetting("cache_quota_lifetime")) * 60)
  65. , m_QuotaUserDefaultCache("uquota", atoi(lpConfig->GetSetting("cache_quota_size")), atoi(lpConfig->GetSetting("cache_quota_lifetime")) * 60)
  66. , m_ObjectsCache("obj", atoll(lpConfig->GetSetting("cache_object_size")), 0)
  67. , m_StoresCache("store", atoi(lpConfig->GetSetting("cache_store_size")), 0)
  68. , m_UserObjectCache("userid", atoi(lpConfig->GetSetting("cache_user_size")), atoi(lpConfig->GetSetting("cache_userdetails_lifetime")) * 60)
  69. , m_UEIdObjectCache("extern", atoi(lpConfig->GetSetting("cache_user_size")), atoi(lpConfig->GetSetting("cache_userdetails_lifetime")) * 60)
  70. , m_UserObjectDetailsCache("abinfo", atoi(lpConfig->GetSetting("cache_userdetails_size")), atoi(lpConfig->GetSetting("cache_userdetails_lifetime")) * 60)
  71. , m_AclCache("acl", atoi(lpConfig->GetSetting("cache_acl_size")), 0)
  72. , m_CellCache("cell", atoll(lpConfig->GetSetting("cache_cell_size")), 0)
  73. , m_ServerDetailsCache("server", atoi(lpConfig->GetSetting("cache_server_size")), atoi(lpConfig->GetSetting("cache_server_lifetime")) * 60)
  74. , m_PropToObjectCache("index1", atoll(lpConfig->GetSetting("cache_indexedobject_size")), 0)
  75. , m_ObjectToPropCache("index2", atoll(lpConfig->GetSetting("cache_indexedobject_size")), 0)
  76. {
  77. /* Initial cleaning/initialization of cache */
  78. PurgeCache(PURGE_CACHE_ALL);
  79. }
  80. ECCacheManager::~ECCacheManager()
  81. {
  82. PurgeCache(PURGE_CACHE_ALL);
  83. }
  84. ECRESULT ECCacheManager::PurgeCache(unsigned int ulFlags)
  85. {
  86. ECRESULT er = erSuccess;
  87. LOG_CACHE_DEBUG("Purge cache, flags 0x%08X", ulFlags);
  88. // cache mutex items
  89. ulock_rec l_cache(m_hCacheMutex);
  90. if (ulFlags & PURGE_CACHE_QUOTA)
  91. m_QuotaCache.ClearCache();
  92. if (ulFlags & PURGE_CACHE_QUOTADEFAULT)
  93. m_QuotaUserDefaultCache.ClearCache();
  94. if (ulFlags & PURGE_CACHE_OBJECTS)
  95. m_ObjectsCache.ClearCache();
  96. if (ulFlags & PURGE_CACHE_STORES)
  97. m_StoresCache.ClearCache();
  98. if (ulFlags & PURGE_CACHE_ACL)
  99. m_AclCache.ClearCache();
  100. l_cache.unlock();
  101. // Cell cache mutex
  102. ulock_rec l_cells(m_hCacheCellsMutex);
  103. if(ulFlags & PURGE_CACHE_CELL)
  104. m_CellCache.ClearCache();
  105. l_cells.unlock();
  106. // Indexed properties mutex
  107. ulock_rec l_prop(m_hCacheIndPropMutex);
  108. if (ulFlags & PURGE_CACHE_INDEX1)
  109. m_PropToObjectCache.ClearCache();
  110. if (ulFlags & PURGE_CACHE_INDEX2)
  111. m_ObjectToPropCache.ClearCache();
  112. l_prop.unlock();
  113. ulock_normal l_xp(m_hExcludedIndexPropertiesMutex);
  114. if (ulFlags & PURGE_CACHE_INDEXEDPROPERTIES)
  115. m_setExcludedIndexProperties.clear();
  116. l_xp.unlock();
  117. l_cache.lock();
  118. if (ulFlags & PURGE_CACHE_USEROBJECT)
  119. m_UserObjectCache.ClearCache();
  120. if (ulFlags & PURGE_CACHE_EXTERNID)
  121. m_UEIdObjectCache.ClearCache();
  122. if (ulFlags & PURGE_CACHE_USERDETAILS)
  123. m_UserObjectDetailsCache.ClearCache();
  124. if (ulFlags & PURGE_CACHE_SERVER)
  125. m_ServerDetailsCache.ClearCache();
  126. l_cache.unlock();
  127. return er;
  128. }
  129. ECRESULT ECCacheManager::Update(unsigned int ulType, unsigned int ulObjId)
  130. {
  131. ECRESULT er = erSuccess;
  132. switch(ulType)
  133. {
  134. case fnevObjectModified:
  135. LOG_CACHE_DEBUG("Remove cache ACLs, cell, objects for object %d", ulObjId);
  136. _DelACLs(ulObjId);
  137. _DelCell(ulObjId);
  138. _DelObject(ulObjId);
  139. break;
  140. case fnevObjectDeleted:
  141. LOG_CACHE_DEBUG("Remove cache ACLs, cell, objects and store for object %d", ulObjId);
  142. _DelObject(ulObjId);
  143. _DelStore(ulObjId);
  144. _DelACLs(ulObjId);
  145. _DelCell(ulObjId);
  146. break;
  147. case fnevObjectMoved:
  148. LOG_CACHE_DEBUG("Remove cache cell, objects and store for object %d", ulObjId);
  149. _DelStore(ulObjId);
  150. _DelObject(ulObjId);
  151. _DelCell(ulObjId);
  152. break;
  153. default:
  154. //Do nothing
  155. LOG_CACHE_DEBUG("Update cache, action type %d, objectid %d", ulType, ulObjId);
  156. break;
  157. }
  158. return er;
  159. }
  160. ECRESULT ECCacheManager::UpdateUser(unsigned int ulUserId)
  161. {
  162. std::string strExternId;
  163. objectclass_t ulClass;
  164. LOG_USERCACHE_DEBUG("Remove user id %d from the cache", ulUserId);
  165. if (_GetUserObject(ulUserId, &ulClass, NULL, &strExternId, NULL) == erSuccess)
  166. _DelUEIdObject(strExternId, ulClass);
  167. _DelUserObject(ulUserId);
  168. _DelUserObjectDetails(ulUserId);
  169. _DelQuota(ulUserId, false);
  170. _DelQuota(ulUserId, true);
  171. return erSuccess;
  172. }
  173. ECRESULT ECCacheManager::_GetObject(unsigned int ulObjId, unsigned int *ulParent, unsigned int *ulOwner, unsigned int *ulFlags, unsigned int *ulType)
  174. {
  175. ECRESULT er;
  176. ECsObjects *sObject;
  177. scoped_rlock lock(m_hCacheMutex);
  178. er = m_ObjectsCache.GetCacheItem(ulObjId, &sObject);
  179. if(er != erSuccess)
  180. return er;
  181. assert((sObject->ulType != MAPI_FOLDER && (sObject->ulFlags & ~(MAPI_ASSOCIATED | MSGFLAG_DELETED)) == 0) || sObject->ulType == MAPI_FOLDER);
  182. if(ulParent)
  183. *ulParent = sObject->ulParent;
  184. if(ulOwner)
  185. *ulOwner = sObject->ulOwner;
  186. if(ulFlags)
  187. *ulFlags = sObject->ulFlags;
  188. if(ulType)
  189. *ulType = sObject->ulType;
  190. return erSuccess;
  191. }
  192. ECRESULT ECCacheManager::SetObject(unsigned int ulObjId, unsigned int ulParent, unsigned int ulOwner, unsigned int ulFlags, unsigned int ulType)
  193. {
  194. ECRESULT er = erSuccess;
  195. ECsObjects sObjects;
  196. if(ulParent == 0 || ulObjId == 0 || ulOwner == 0)
  197. return 1;
  198. assert((ulType != MAPI_FOLDER && (ulFlags & ~(MAPI_ASSOCIATED | MSGFLAG_DELETED)) == 0) || ulType == MAPI_FOLDER);
  199. sObjects.ulParent = ulParent;
  200. sObjects.ulOwner = ulOwner;
  201. sObjects.ulFlags = ulFlags;
  202. sObjects.ulType = ulType;
  203. scoped_rlock lock(m_hCacheMutex);
  204. er = m_ObjectsCache.AddCacheItem(ulObjId, sObjects);
  205. LOG_CACHE_DEBUG("Set cache object id %d, parent %d, owner %d, flags %d, type %d", ulObjId, ulParent, ulOwner, ulFlags, ulType);
  206. return er;
  207. }
  208. ECRESULT ECCacheManager::_DelObject(unsigned int ulObjId)
  209. {
  210. scoped_rlock lock(m_hCacheMutex);
  211. return m_ObjectsCache.RemoveCacheItem(ulObjId);
  212. }
  213. ECRESULT ECCacheManager::_GetStore(unsigned int ulObjId, unsigned int *ulStore, GUID *lpGuid, unsigned int *lpulType)
  214. {
  215. ECRESULT er;
  216. ECsStores *sStores;
  217. scoped_rlock lock(m_hCacheMutex);
  218. er = m_StoresCache.GetCacheItem(ulObjId, &sStores);
  219. if(er != erSuccess)
  220. return er;
  221. if(ulStore)
  222. *ulStore = sStores->ulStore;
  223. if (lpulType != NULL)
  224. *lpulType = sStores->ulType;
  225. if(lpGuid)
  226. memcpy(lpGuid, &sStores->guidStore, sizeof(GUID) );
  227. return erSuccess;
  228. }
  229. ECRESULT ECCacheManager::SetStore(unsigned int ulObjId, unsigned int ulStore,
  230. const GUID *lpGuid, unsigned int ulType)
  231. {
  232. ECRESULT er = erSuccess;
  233. ECsStores sStores;
  234. sStores.ulStore = ulStore;
  235. sStores.guidStore = *lpGuid;
  236. sStores.ulType = ulType;
  237. scoped_rlock lock(m_hCacheMutex);
  238. er = m_StoresCache.AddCacheItem(ulObjId, sStores);
  239. LOG_CACHE_DEBUG("Set store cache id %d, store %d, type %d, guid %s", ulObjId, ulStore, ulType, ((lpGuid)?bin2hex(sizeof(GUID), (const unsigned char*)lpGuid).c_str(): "NULL"));
  240. return er;
  241. }
  242. ECRESULT ECCacheManager::_DelStore(unsigned int ulObjId)
  243. {
  244. scoped_rlock lock(m_hCacheMutex);
  245. return m_StoresCache.RemoveCacheItem(ulObjId);
  246. }
  247. ECRESULT ECCacheManager::GetOwner(unsigned int ulObjId, unsigned int *ulOwner)
  248. {
  249. ECRESULT er = erSuccess;
  250. bool bCacheResult = false;
  251. if(_GetObject(ulObjId, NULL, ulOwner, NULL, NULL) == erSuccess) {
  252. bCacheResult = true;
  253. goto exit;
  254. }
  255. er = GetObject(ulObjId, NULL, ulOwner, NULL);
  256. exit:
  257. if (er != erSuccess)
  258. LOG_CACHE_DEBUG("Get Owner for id %d error 0x%08X", ulObjId, er);
  259. else
  260. LOG_CACHE_DEBUG("Get Owner for id %d result [%s]: owner %d", ulObjId, ((bCacheResult)?"C":"D"), *ulOwner);
  261. return er;
  262. }
  263. ECRESULT ECCacheManager::GetParent(unsigned int ulObjId, unsigned int *lpulParent)
  264. {
  265. ECRESULT er;
  266. unsigned int ulParent = 0;
  267. er = GetObject(ulObjId, &ulParent, NULL, NULL);
  268. if(er != erSuccess)
  269. return er;
  270. if (ulParent == CACHE_NO_PARENT)
  271. return KCERR_NOT_FOUND;
  272. *lpulParent = ulParent;
  273. return erSuccess;
  274. }
  275. ECRESULT ECCacheManager::QueryParent(unsigned int ulObjId, unsigned int *lpulParent)
  276. {
  277. return _GetObject(ulObjId, lpulParent, nullptr, nullptr, nullptr);
  278. }
  279. // Get the parent of the specified object
  280. ECRESULT ECCacheManager::GetObject(unsigned int ulObjId, unsigned int *lpulParent, unsigned int *lpulOwner, unsigned int *lpulFlags, unsigned int *lpulType)
  281. {
  282. ECRESULT er = erSuccess;
  283. DB_RESULT lpDBResult;
  284. DB_ROW lpDBRow = NULL;
  285. std::string strQuery;
  286. ECDatabase *lpDatabase = NULL;
  287. unsigned int ulParent = 0, ulOwner = 0, ulFlags = 0, ulType = 0;
  288. bool bCacheResult = false;
  289. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  290. if(er != erSuccess)
  291. goto exit;
  292. // first check the cache if the item exists
  293. if(_GetObject(ulObjId, &ulParent, &ulOwner, &ulFlags, &ulType) == erSuccess) {
  294. if(lpulParent)
  295. *lpulParent = ulParent;
  296. if(lpulOwner)
  297. *lpulOwner = ulOwner;
  298. if(lpulFlags)
  299. *lpulFlags = ulFlags;
  300. if(lpulType)
  301. *lpulType = ulType;
  302. bCacheResult = true;
  303. goto exit;
  304. }
  305. strQuery = "SELECT hierarchy.parent, hierarchy.owner, hierarchy.flags, hierarchy.type FROM hierarchy WHERE hierarchy.id = " + stringify(ulObjId) + " LIMIT 1";
  306. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  307. if(er != erSuccess)
  308. goto exit;
  309. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  310. if(lpDBRow == NULL) {
  311. er = KCERR_NOT_FOUND;
  312. goto exit;
  313. }
  314. if(lpDBRow[1] == NULL || lpDBRow[2] == NULL || lpDBRow[3] == NULL) {
  315. // owner or flags should not be NULL
  316. er = KCERR_DATABASE_ERROR;
  317. ec_log_err("ECCacheManager::GetObject(): NULL in columns");
  318. goto exit;
  319. }
  320. ulParent = lpDBRow[0] == NULL ? CACHE_NO_PARENT : atoui(lpDBRow[0]);
  321. ulOwner = atoui(lpDBRow[1]);
  322. ulFlags = atoui(lpDBRow[2]);
  323. ulType = atoui(lpDBRow[3]);
  324. if(lpulParent)
  325. *lpulParent = ulParent;
  326. if(lpulOwner)
  327. *lpulOwner = ulOwner;
  328. if(lpulFlags)
  329. *lpulFlags = ulFlags;
  330. if(lpulType)
  331. *lpulType = ulType;
  332. SetObject(ulObjId, ulParent, ulOwner, ulFlags, ulType);
  333. exit:
  334. if (er != erSuccess)
  335. LOG_CACHE_DEBUG("Get object id %d error 0x%08x", ulObjId, er);
  336. else
  337. LOG_CACHE_DEBUG("Get object id %d result [%s]: parent %d owner %d flags %d type %d", ulObjId, ((bCacheResult)?"C":"D"), ulParent, ulOwner, ulFlags, ulType);
  338. return er;
  339. }
  340. ECRESULT ECCacheManager::GetObjects(const std::list<sObjectTableKey> &lstObjects,
  341. std::map<sObjectTableKey, ECsObjects> &mapObjects)
  342. {
  343. ECRESULT er = erSuccess;
  344. DB_RESULT lpDBResult;
  345. DB_ROW lpDBRow = NULL;
  346. std::string strQuery;
  347. ECDatabase *lpDatabase = NULL;
  348. unsigned int ulObjId = 0;
  349. sObjectTableKey key;
  350. ECsObjects *lpsObject = NULL;
  351. ECsObjects sObject;
  352. std::set<sObjectTableKey> setUncached;
  353. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  354. if(er != erSuccess)
  355. goto exit;
  356. {
  357. // Get everything from the cache that we can
  358. scoped_rlock lock(m_hCacheMutex);
  359. for (const auto &key : lstObjects)
  360. if (m_ObjectsCache.GetCacheItem(key.ulObjId, &lpsObject) == erSuccess)
  361. mapObjects[key] = *lpsObject;
  362. else
  363. setUncached.insert(key);
  364. }
  365. if(!setUncached.empty()) {
  366. // Get uncached items from SQL
  367. strQuery = "SELECT id, parent, owner, flags, type FROM hierarchy WHERE id IN(";
  368. for (const auto &key : setUncached) {
  369. strQuery += stringify(key.ulObjId);
  370. strQuery += ",";
  371. }
  372. strQuery.resize(strQuery.size()-1);
  373. strQuery += ")";
  374. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  375. if (er != erSuccess)
  376. goto exit;
  377. while((lpDBRow = lpDatabase->FetchRow(lpDBResult))) {
  378. if(!lpDBRow[0] || !lpDBRow[1] || !lpDBRow[2] || !lpDBRow[3])
  379. continue;
  380. ulObjId = atoui(lpDBRow[0]);
  381. sObject.ulParent = atoui(lpDBRow[1]);
  382. sObject.ulOwner = atoui(lpDBRow[2]);
  383. sObject.ulFlags = atoui(lpDBRow[3]);
  384. sObject.ulType = atoui(lpDBRow[4]);
  385. key.ulObjId = ulObjId;
  386. key.ulOrderId = 0;
  387. mapObjects[key] = sObject;
  388. }
  389. }
  390. if (mapObjects.size() < lstObjects.size())
  391. LOG_CACHE_DEBUG("Get objects ids warning %zu objects not found",
  392. lstObjects.size() - mapObjects.size());
  393. exit:
  394. if (er != erSuccess)
  395. LOG_CACHE_DEBUG("Get object ids error 0x%08x", er);
  396. else
  397. LOG_CACHE_DEBUG("Get object ids total ids %zu from disk %zu",
  398. lstObjects.size(), setUncached.size());
  399. return er;
  400. }
  401. ECRESULT ECCacheManager::GetObjectsFromProp(unsigned int ulTag,
  402. const std::vector<unsigned int> &cbdata,
  403. const std::vector<unsigned char *> &lpdata,
  404. std::map<ECsIndexProp, unsigned int> &mapObjects)
  405. {
  406. ECRESULT er = erSuccess;
  407. ECDatabase *lpDatabase = NULL;
  408. std::string strQuery;
  409. DB_RESULT lpDBResult;
  410. DB_ROW lpDBRow = NULL;
  411. DB_LENGTHS lpDBLen = NULL;
  412. unsigned int objid;
  413. std::vector<size_t> uncached;
  414. for (size_t i = 0; i < lpdata.size(); ++i) {
  415. if (QueryObjectFromProp(ulTag, cbdata[i], lpdata[i], &objid) == erSuccess) {
  416. ECsIndexProp p(PROP_ID(ulTag), lpdata[i], cbdata[i]);
  417. mapObjects[std::move(p)] = objid;
  418. } else {
  419. uncached.push_back(i);
  420. }
  421. }
  422. if (!uncached.empty()) {
  423. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  424. if (er != erSuccess)
  425. goto exit;
  426. strQuery = "SELECT hierarchyid, val_binary FROM indexedproperties FORCE INDEX(bin) WHERE tag="+stringify(ulTag)+" AND val_binary IN(";
  427. for (size_t j = 0; j < uncached.size(); ++j) {
  428. strQuery += lpDatabase->EscapeBinary(lpdata[j], cbdata[j]);
  429. strQuery += ",";
  430. }
  431. strQuery.resize(strQuery.size() - 1);
  432. strQuery += ")";
  433. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  434. if (er != erSuccess)
  435. goto exit;
  436. while ((lpDBRow = lpDatabase->FetchRow(lpDBResult)) != NULL) {
  437. lpDBLen = lpDatabase->FetchRowLengths(lpDBResult);
  438. ECsIndexProp p(PROP_ID(ulTag), reinterpret_cast<unsigned char *>(lpDBRow[1]), lpDBLen[1]);
  439. mapObjects[std::move(p)] = atoui(lpDBRow[0]);
  440. }
  441. }
  442. if (mapObjects.size() < lpdata.size())
  443. LOG_CACHE_DEBUG("Get objects ids warning %zu objects not found",
  444. lpdata.size() - mapObjects.size());
  445. exit:
  446. if (er != erSuccess)
  447. LOG_CACHE_DEBUG("Get object ids from props error: 0x%08x", er);
  448. else
  449. LOG_CACHE_DEBUG("Get object ids from props total ids %zu from disk %zu", cbdata.size(), uncached.size());
  450. return er;
  451. }
  452. // Get the store that the specified object belongs to
  453. ECRESULT ECCacheManager::GetStore(unsigned int ulObjId, unsigned int *lpulStore, GUID *lpGuid, unsigned int maxdepth)
  454. {
  455. LOG_CACHE_DEBUG("Get store id %d >", ulObjId);
  456. return GetStoreAndType(ulObjId, lpulStore, lpGuid, NULL, maxdepth);
  457. }
  458. // Get the store that the specified object belongs to
  459. ECRESULT ECCacheManager::GetStoreAndType(unsigned int ulObjId, unsigned int *lpulStore, GUID *lpGuid, unsigned int *lpulType, unsigned int maxdepth)
  460. {
  461. ECRESULT er = erSuccess;
  462. DB_RESULT lpDBResult;
  463. DB_ROW lpDBRow = NULL;
  464. std::string strQuery;
  465. ECDatabase *lpDatabase = NULL;
  466. unsigned int ulSubObjId = 0;
  467. unsigned int ulStore = 0;
  468. unsigned int ulType = 0;
  469. GUID guid;
  470. bool bCacheResult = false;
  471. if(maxdepth <= 0)
  472. return KCERR_NOT_FOUND;
  473. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  474. if(er != erSuccess)
  475. goto exit;
  476. // first check the cache if we already know the store for this object
  477. if(_GetStore(ulObjId, &ulStore, &guid, &ulType) == erSuccess) {
  478. bCacheResult = true;
  479. goto found;
  480. }
  481. // Get our parent folder
  482. if(GetParent(ulObjId, &ulSubObjId) != erSuccess) {
  483. // No parent, this must be the top-level item, get the store data from here
  484. strQuery = "SELECT hierarchy_id, guid, type FROM stores WHERE hierarchy_id = " + stringify(ulObjId) + " LIMIT 1";
  485. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  486. if(er != erSuccess)
  487. goto exit;
  488. if(lpDatabase->GetNumRows(lpDBResult) < 1) {
  489. er = KCERR_NOT_FOUND;
  490. goto exit;
  491. }
  492. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  493. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL) {
  494. er = KCERR_DATABASE_ERROR;
  495. ec_log_err("ECCacheManager::GetStoreAndType(): NULL in columns");
  496. goto exit;
  497. }
  498. ulStore = atoi(lpDBRow[0]);
  499. memcpy(&guid, lpDBRow[1], sizeof(GUID));
  500. ulType = atoi(lpDBRow[2]);
  501. } else {
  502. // We have a parent, get the store for our parent by recursively calling ourselves
  503. er = GetStoreAndType(ulSubObjId, &ulStore, &guid, &ulType, maxdepth-1);
  504. if(er != erSuccess)
  505. goto exit;
  506. }
  507. // insert the item into the cache
  508. SetStore(ulObjId, ulStore, &guid, ulType);
  509. found:
  510. if(lpulStore)
  511. *lpulStore = ulStore;
  512. if(lpGuid)
  513. *lpGuid = guid;
  514. if(lpulType)
  515. *lpulType = ulType;
  516. exit:
  517. if (er != erSuccess)
  518. LOG_CACHE_DEBUG("Get store and type %d error 0x%08x", ulObjId, er);
  519. else
  520. LOG_CACHE_DEBUG("Get store and type %d result [%s]: store %d, type %d, guid %s", ulObjId, ((bCacheResult)?"C":"D"), ulStore, ulType, bin2hex(sizeof(GUID), (const unsigned char*)&guid).c_str());
  521. return er;
  522. }
  523. ECRESULT ECCacheManager::GetUserObject(unsigned int ulUserId, objectid_t *lpExternId, unsigned int *lpulCompanyId, std::string *lpstrSignature)
  524. {
  525. ECRESULT er = erSuccess;
  526. DB_RESULT lpDBResult;
  527. DB_ROW lpDBRow = NULL;
  528. DB_LENGTHS lpDBLen = NULL;
  529. std::string strQuery;
  530. ECDatabase *lpDatabase = NULL;
  531. objectclass_t ulClass;
  532. unsigned int ulCompanyId;
  533. std::string externid;
  534. std::string signature;
  535. bool bCacheResult = false;
  536. // first check the cache if we already know the external id for this user
  537. if (_GetUserObject(ulUserId, &ulClass, lpulCompanyId, &externid, lpstrSignature) == erSuccess) {
  538. if (lpExternId) {
  539. lpExternId->id = externid;
  540. lpExternId->objclass = ulClass;
  541. }
  542. bCacheResult = true;
  543. goto exit;
  544. }
  545. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  546. if (er != erSuccess)
  547. goto exit;
  548. er = lpDatabase->DoSelect("SELECT externid, objectclass, signature, company FROM users "
  549. "WHERE id=" + stringify(ulUserId) + " LIMIT 1", &lpDBResult);
  550. if (er != erSuccess) {
  551. er = KCERR_DATABASE_ERROR;
  552. ec_log_err("ECCacheManager::GetUserObject(): NULL in columns");
  553. goto exit;
  554. }
  555. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  556. lpDBLen = lpDatabase->FetchRowLengths(lpDBResult);
  557. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL || lpDBRow[3] == NULL) {
  558. er = KCERR_NOT_FOUND;
  559. goto exit;
  560. }
  561. ulClass = (objectclass_t)atoui(lpDBRow[1]);
  562. ulCompanyId = atoui(lpDBRow[3]);
  563. externid.assign(lpDBRow[0], lpDBLen[0]);
  564. signature.assign(lpDBRow[2], lpDBLen[2]);
  565. // insert the item into the cache
  566. _AddUserObject(ulUserId, ulClass, ulCompanyId, externid, signature);
  567. if (lpExternId) {
  568. lpExternId->id = externid;
  569. lpExternId->objclass = ulClass;
  570. }
  571. if(lpulCompanyId)
  572. *lpulCompanyId = ulCompanyId;
  573. if(lpstrSignature)
  574. *lpstrSignature = signature;
  575. exit:
  576. if (er != erSuccess)
  577. LOG_USERCACHE_DEBUG("Get user object for user %d error 0x%08x", ulUserId, er);
  578. else
  579. LOG_USERCACHE_DEBUG("Get user object for user %d result [%s]: externid '%s', class %d, companyid %d, signature '%s'", ulUserId, ((bCacheResult)?"C":"D"), bin2hex(externid).c_str(), ulClass, ((lpulCompanyId)?*lpulCompanyId:-1), ((lpstrSignature)?bin2hex(*lpstrSignature).c_str():"-") );
  580. return er;
  581. }
  582. ECRESULT ECCacheManager::GetUserDetails(unsigned int ulUserId, objectdetails_t *details)
  583. {
  584. ECRESULT er = erSuccess;
  585. er = _GetUserObjectDetails(ulUserId, details);
  586. // on error, ECUserManagement will update the cache
  587. if (er != erSuccess)
  588. LOG_USERCACHE_DEBUG("Get user details for userid %d not found, error 0x%08x", ulUserId, er);
  589. else
  590. LOG_USERCACHE_DEBUG("Get user details for userid %d result: %s", ulUserId, details->ToStr().c_str() );
  591. return er;
  592. }
  593. ECRESULT ECCacheManager::SetUserDetails(unsigned int ulUserId,
  594. const objectdetails_t *details)
  595. {
  596. return _AddUserObjectDetails(ulUserId, details);
  597. }
  598. ECRESULT ECCacheManager::GetUserObject(const objectid_t &sExternId, unsigned int *lpulUserId, unsigned int *lpulCompanyId, std::string *lpstrSignature)
  599. {
  600. ECRESULT er = erSuccess;
  601. DB_RESULT lpDBResult;
  602. DB_ROW lpDBRow = NULL;
  603. DB_LENGTHS lpDBLen = NULL;
  604. std::string strQuery;
  605. ECDatabase *lpDatabase = NULL;
  606. unsigned int ulCompanyId;
  607. unsigned int ulUserId;
  608. std::string signature;
  609. objectclass_t objclass = sExternId.objclass;
  610. bool bCacheResult = false;
  611. if (sExternId.id.empty()) {
  612. er = KCERR_DATABASE_ERROR;
  613. //assert(false);
  614. goto exit;
  615. }
  616. // first check the cache if we already know the external id for this user
  617. if (_GetUEIdObject(sExternId.id, sExternId.objclass, lpulCompanyId, lpulUserId, lpstrSignature) == erSuccess) {
  618. bCacheResult = true;
  619. goto exit;
  620. }
  621. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  622. if (er != erSuccess)
  623. goto exit;
  624. strQuery =
  625. "SELECT id, signature, company, objectclass FROM users "
  626. "WHERE externid='" + lpDatabase->Escape(sExternId.id) + "' "
  627. "AND " + OBJECTCLASS_COMPARE_SQL("objectclass", sExternId.objclass) + " LIMIT 1";
  628. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  629. if (er != erSuccess) {
  630. er = KCERR_DATABASE_ERROR;
  631. ec_log_err("ECCacheManager::GetUserObject(): query failed %x", er);
  632. goto exit;
  633. }
  634. // TODO: check, should return 1 answer
  635. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  636. lpDBLen = lpDatabase->FetchRowLengths(lpDBResult);
  637. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL) {
  638. er = KCERR_NOT_FOUND;
  639. goto exit;
  640. }
  641. ulUserId = atoui(lpDBRow[0]);
  642. signature.assign(lpDBRow[1], lpDBLen[1]);
  643. ulCompanyId = atoui(lpDBRow[2]);
  644. // possibly update objectclass from database, to add the correct info in the cache
  645. if (OBJECTCLASS_ISTYPE(sExternId.objclass))
  646. objclass = (objectclass_t)atoi(lpDBRow[3]);
  647. // insert the item into the cache
  648. _AddUEIdObject(sExternId.id, objclass, ulCompanyId, ulUserId, signature);
  649. if(lpulCompanyId)
  650. *lpulCompanyId = ulCompanyId;
  651. if(lpulUserId)
  652. *lpulUserId = ulUserId;
  653. if(lpstrSignature)
  654. *lpstrSignature = signature;
  655. exit:
  656. if (er != erSuccess)
  657. LOG_USERCACHE_DEBUG("Get user object done. error 0x%08X", er);
  658. else
  659. LOG_USERCACHE_DEBUG("Get user object from externid '%s', class %d result [%s]: company %d, userid %d, signature '%s'" , bin2hex(sExternId.id).c_str(), sExternId.objclass, ((bCacheResult)?"C":"D"), ((lpulCompanyId)?*lpulCompanyId:-1), ((lpulUserId)?*lpulUserId:-1), ((lpstrSignature)?bin2hex(*lpstrSignature).c_str():"-") );
  660. return er;
  661. }
  662. ECRESULT ECCacheManager::GetUserObjects(const list<objectid_t> &lstExternObjIds, map<objectid_t, unsigned int> *lpmapLocalObjIds)
  663. {
  664. ECRESULT er = erSuccess;
  665. DB_RESULT lpDBResult;
  666. DB_ROW lpDBRow = NULL;
  667. DB_LENGTHS lpDBLen = NULL;
  668. std::string strQuery;
  669. ECDatabase *lpDatabase = NULL;
  670. list<objectid_t> lstExternIds;
  671. list<objectid_t>::const_iterator iter;
  672. objectid_t sExternId;
  673. string strSignature;
  674. unsigned int ulLocalId = 0;
  675. unsigned int ulCompanyId;
  676. // Collect as many objects from cache as possible,
  677. // everything we couldn't find must be collected from the database
  678. LOG_USERCACHE_DEBUG("Get User Objects. requested objects %zu",
  679. lstExternObjIds.size());
  680. for (const auto &objid : lstExternObjIds) {
  681. LOG_USERCACHE_DEBUG(" Get user objects from externid \"%s\", class %d",
  682. bin2hex(objid.id).c_str(), objid.objclass);
  683. if (_GetUEIdObject(objid.id, objid.objclass, NULL, &ulLocalId, NULL) == erSuccess)
  684. /* Object was found in cache. */
  685. lpmapLocalObjIds->insert(make_pair(objid, ulLocalId));
  686. else
  687. /* Object was not found in cache. */
  688. lstExternIds.push_back(objid);
  689. }
  690. // Check if all objects have been collected from the cache
  691. if (lstExternIds.empty())
  692. goto exit;
  693. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  694. if (er != erSuccess)
  695. goto exit;
  696. strQuery = "SELECT id, externid, objectclass, signature, company FROM users WHERE ";
  697. for (auto iter = lstExternIds.cbegin();
  698. iter != lstExternIds.cend(); ++iter) {
  699. if (iter != lstExternIds.cbegin())
  700. strQuery += " OR ";
  701. strQuery +=
  702. "(" + OBJECTCLASS_COMPARE_SQL("objectclass", iter->objclass) +
  703. " AND externid = '" + lpDatabase->Escape(iter->id) + "')";
  704. }
  705. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  706. if (er != erSuccess) {
  707. ec_log_err("ECCacheManager::GetUserObjects() query failed %x", er);
  708. er = KCERR_DATABASE_ERROR;
  709. goto exit;
  710. }
  711. while (TRUE) {
  712. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  713. lpDBLen = lpDatabase->FetchRowLengths(lpDBResult);
  714. if (lpDBRow == NULL || lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL || lpDBRow[3] == NULL || lpDBRow[4] == NULL)
  715. break;
  716. ulLocalId = atoi(lpDBRow[0]);
  717. sExternId.id.assign(lpDBRow[1], lpDBLen[1]);
  718. sExternId.objclass = (objectclass_t)atoi(lpDBRow[2]);
  719. strSignature.assign(lpDBRow[3], lpDBLen[3]);
  720. ulCompanyId = atoi(lpDBRow[4]);
  721. lpmapLocalObjIds->insert(make_pair(sExternId, ulLocalId));
  722. _AddUEIdObject(sExternId.id, sExternId.objclass, ulCompanyId, ulLocalId, strSignature);
  723. LOG_USERCACHE_DEBUG(" Get user objects result company %d, userid %d, signature '%s'", ulCompanyId, ulLocalId, bin2hex(strSignature).c_str());
  724. }
  725. // From this point you can have less items in lpmapLocalObjIds than requested in lstExternObjIds
  726. exit:
  727. if (er != erSuccess)
  728. LOG_USERCACHE_DEBUG("Get User Objects done. Error 0x%08X", er);
  729. else
  730. LOG_USERCACHE_DEBUG("Get User Objects done. Returned objects %zu",
  731. lpmapLocalObjIds->size());
  732. return er;
  733. }
  734. ECRESULT ECCacheManager::_AddUserObject(unsigned int ulUserId,
  735. const objectclass_t &ulClass, unsigned int ulCompanyId,
  736. const std::string &strExternId, const std::string &strSignature)
  737. {
  738. ECsUserObject sData;
  739. scoped_rlock lock(m_hCacheMutex);
  740. if (OBJECTCLASS_ISTYPE(ulClass)) {
  741. LOG_USERCACHE_DEBUG("_Add user object. userid %d, class %d, companyid %d, externid '%s', signature '%s'. error incomplete object", ulUserId, ulClass, ulCompanyId, bin2hex(strExternId).c_str(), bin2hex(strSignature).c_str());
  742. return erSuccess; // do not add incomplete data into the cache
  743. }
  744. LOG_USERCACHE_DEBUG("_Add user object. userid %d, class %d, companyid %d, externid '%s', signature '%s'", ulUserId, ulClass, ulCompanyId, bin2hex(strExternId).c_str(), bin2hex(strSignature).c_str());
  745. sData.ulClass = ulClass;
  746. sData.ulCompanyId = ulCompanyId;
  747. sData.strExternId = strExternId;
  748. sData.strSignature = strSignature;
  749. return m_UserObjectCache.AddCacheItem(ulUserId, sData);
  750. }
  751. ECRESULT ECCacheManager::_GetUserObject(unsigned int ulUserId, objectclass_t* lpulClass, unsigned int *lpulCompanyId,
  752. std::string* lpstrExternId, std::string* lpstrSignature)
  753. {
  754. ECRESULT er;
  755. ECsUserObject *sData;
  756. scoped_rlock lock(m_hCacheMutex);
  757. er = m_UserObjectCache.GetCacheItem(ulUserId, &sData);
  758. if(er != erSuccess)
  759. return er;
  760. if(lpulClass)
  761. *lpulClass = sData->ulClass;
  762. if(lpulCompanyId)
  763. *lpulCompanyId = sData->ulCompanyId;
  764. if(lpstrExternId)
  765. *lpstrExternId = sData->strExternId;
  766. if(lpstrSignature)
  767. *lpstrSignature = sData->strSignature;
  768. return erSuccess;
  769. }
  770. ECRESULT ECCacheManager::_DelUserObject(unsigned int ulUserId)
  771. {
  772. scoped_rlock lock(m_hCacheMutex);
  773. // Remove the user
  774. return m_UserObjectCache.RemoveCacheItem(ulUserId);
  775. }
  776. ECRESULT ECCacheManager::_AddUserObjectDetails(unsigned int ulUserId,
  777. const objectdetails_t *details)
  778. {
  779. ECsUserObjectDetails sObjectDetails;
  780. scoped_rlock lock(m_hCacheMutex);
  781. if (details == NULL)
  782. return KCERR_INVALID_PARAMETER;
  783. LOG_USERCACHE_DEBUG("_Add user details. userid %d, %s", ulUserId, details->ToStr().c_str() );
  784. sObjectDetails.sDetails = *details;
  785. return m_UserObjectDetailsCache.AddCacheItem(ulUserId, sObjectDetails);
  786. }
  787. ECRESULT ECCacheManager::_GetUserObjectDetails(unsigned int ulUserId, objectdetails_t *details)
  788. {
  789. ECRESULT er;
  790. ECsUserObjectDetails *sObjectDetails;
  791. scoped_rlock lock(m_hCacheMutex);
  792. if (details == NULL)
  793. return KCERR_INVALID_PARAMETER;
  794. er = m_UserObjectDetailsCache.GetCacheItem(ulUserId, &sObjectDetails);
  795. if (er != erSuccess)
  796. return er;
  797. *details = sObjectDetails->sDetails;
  798. return erSuccess;
  799. }
  800. ECRESULT ECCacheManager::_DelUserObjectDetails(unsigned int ulUserId)
  801. {
  802. scoped_rlock lock(m_hCacheMutex);
  803. // Remove the user details
  804. return m_UserObjectDetailsCache.RemoveCacheItem(ulUserId);
  805. }
  806. ECRESULT ECCacheManager::_AddUEIdObject(const std::string &strExternId,
  807. const objectclass_t &ulClass, unsigned int ulCompanyId,
  808. unsigned int ulUserId, const std::string &strSignature)
  809. {
  810. ECsUEIdKey sKey;
  811. ECsUEIdObject sData;
  812. scoped_rlock lock(m_hCacheMutex);
  813. if (OBJECTCLASS_ISTYPE(ulClass))
  814. return erSuccess; // do not add incomplete data into the cache
  815. sData.ulCompanyId = ulCompanyId;
  816. sData.ulUserId = ulUserId;
  817. sData.strSignature = strSignature;
  818. sKey.ulClass = ulClass;
  819. sKey.strExternId = strExternId;
  820. return m_UEIdObjectCache.AddCacheItem(sKey, sData);
  821. }
  822. ECRESULT ECCacheManager::_GetUEIdObject(const std::string &strExternId,
  823. objectclass_t ulClass, unsigned int *lpulCompanyId,
  824. unsigned int *lpulUserId, std::string *lpstrSignature)
  825. {
  826. ECRESULT er;
  827. ECsUEIdKey sKey;
  828. ECsUEIdObject *sData;
  829. sKey.ulClass = ulClass;
  830. sKey.strExternId = strExternId;
  831. scoped_rlock lock(m_hCacheMutex);
  832. er = m_UEIdObjectCache.GetCacheItem(sKey, &sData);
  833. if(er != erSuccess)
  834. return er;
  835. if(lpulCompanyId)
  836. *lpulCompanyId = sData->ulCompanyId;
  837. if(lpulUserId)
  838. *lpulUserId = sData->ulUserId;
  839. if(lpstrSignature)
  840. *lpstrSignature = sData->strSignature;
  841. return erSuccess;
  842. }
  843. ECRESULT ECCacheManager::_DelUEIdObject(const std::string &strExternId,
  844. objectclass_t ulClass)
  845. {
  846. ECRESULT er = erSuccess;
  847. ECsUEIdKey sKey;
  848. LOG_USERCACHE_DEBUG("Remove user externid '%s' class %d", bin2hex(strExternId).c_str(), ulClass);
  849. // Remove the user
  850. sKey.strExternId = strExternId;
  851. sKey.ulClass = ulClass;
  852. scoped_rlock lock(m_hCacheMutex);
  853. m_UEIdObjectCache.RemoveCacheItem(sKey);
  854. return er;
  855. }
  856. ECRESULT ECCacheManager::GetACLs(unsigned int ulObjId, struct rightsArray **lppRights)
  857. {
  858. ECRESULT er = erSuccess;
  859. DB_RESULT lpResult;
  860. DB_ROW lpRow = NULL;
  861. ECDatabase *lpDatabase = NULL;
  862. std::string strQuery;
  863. struct rightsArray *lpRights = NULL;
  864. unsigned int ulRows = 0;
  865. LOG_USERCACHE_DEBUG("Get ACLs for objectid %d", ulObjId);
  866. /* Try cache first */
  867. if (_GetACLs(ulObjId, lppRights) == erSuccess)
  868. return erSuccess;
  869. /* Failed, get it from the cache */
  870. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  871. if(er != erSuccess)
  872. return er;
  873. strQuery = "SELECT id, type, rights FROM acl WHERE hierarchy_id=" + stringify(ulObjId);
  874. er = lpDatabase->DoSelect(strQuery, &lpResult);
  875. if(er != erSuccess)
  876. return er;
  877. ulRows = lpDatabase->GetNumRows(lpResult);
  878. lpRights = s_alloc<rightsArray>(nullptr);
  879. if (ulRows > 0)
  880. {
  881. lpRights->__size = ulRows;
  882. lpRights->__ptr = s_alloc<rights>(nullptr, ulRows);
  883. memset(lpRights->__ptr, 0, sizeof(struct rights) * ulRows);
  884. for (unsigned int i = 0; i < ulRows; ++i) {
  885. lpRow = lpDatabase->FetchRow(lpResult);
  886. if(lpRow == NULL || lpRow[0] == NULL || lpRow[1] == NULL || lpRow[2] == NULL) {
  887. s_free(nullptr, lpRights->__ptr);
  888. s_free(nullptr, lpRights);
  889. ec_log_err("ECCacheManager::GetACLs(): ROW or COLUMNS null %x", er);
  890. return KCERR_DATABASE_ERROR;
  891. }
  892. lpRights->__ptr[i].ulUserid = atoi(lpRow[0]);
  893. lpRights->__ptr[i].ulType = atoi(lpRow[1]);
  894. lpRights->__ptr[i].ulRights = atoi(lpRow[2]);
  895. LOG_USERCACHE_DEBUG(" Get ACLs result for objectid %d: userid %d, type %d, permissions %d", ulObjId, lpRights->__ptr[i].ulUserid, lpRights->__ptr[i].ulType, lpRights->__ptr[i].ulRights);
  896. }
  897. }
  898. else
  899. memset(lpRights, 0, sizeof *lpRights);
  900. SetACLs(ulObjId, lpRights);
  901. *lppRights = lpRights;
  902. return erSuccess;
  903. }
  904. ECRESULT ECCacheManager::_GetACLs(unsigned int ulObjId, struct rightsArray **lppRights)
  905. {
  906. ECRESULT er;
  907. ECsACLs *sACL;
  908. struct rightsArray *lpRights = NULL;
  909. scoped_rlock lock(m_hCacheMutex);
  910. er = m_AclCache.GetCacheItem(ulObjId, &sACL);
  911. if(er != erSuccess)
  912. return er;
  913. lpRights = s_alloc<rightsArray>(nullptr);
  914. if (sACL->ulACLs > 0)
  915. {
  916. lpRights->__size = sACL->ulACLs;
  917. lpRights->__ptr = s_alloc<rights>(nullptr, sACL->ulACLs);
  918. memset(lpRights->__ptr, 0, sizeof(struct rights) * sACL->ulACLs);
  919. for (unsigned int i = 0; i < sACL->ulACLs; ++i) {
  920. lpRights->__ptr[i].ulType = sACL->aACL[i].ulType;
  921. lpRights->__ptr[i].ulRights = sACL->aACL[i].ulMask;
  922. lpRights->__ptr[i].ulUserid = sACL->aACL[i].ulUserId;
  923. LOG_USERCACHE_DEBUG("_Get ACLs result for objectid %d: userid %d, type %d, permissions %d", ulObjId, lpRights->__ptr[i].ulUserid, lpRights->__ptr[i].ulType, lpRights->__ptr[i].ulRights);
  924. }
  925. }
  926. else
  927. memset(lpRights, 0, sizeof *lpRights);
  928. *lppRights = lpRights;
  929. return erSuccess;
  930. }
  931. ECRESULT ECCacheManager::SetACLs(unsigned int ulObjId,
  932. const struct rightsArray *lpRights)
  933. {
  934. ECsACLs sACLs;
  935. LOG_USERCACHE_DEBUG("Set ACLs for objectid %d", ulObjId);
  936. sACLs.ulACLs = lpRights->__size;
  937. sACLs.aACL.reset(new ECsACLs::ACL[lpRights->__size]);
  938. for (gsoap_size_t i = 0; i < lpRights->__size; ++i) {
  939. sACLs.aACL[i].ulType = lpRights->__ptr[i].ulType;
  940. sACLs.aACL[i].ulMask = lpRights->__ptr[i].ulRights;
  941. sACLs.aACL[i].ulUserId = lpRights->__ptr[i].ulUserid;
  942. LOG_USERCACHE_DEBUG("Set ACLs for objectid %d: userid %d, type %d, permissions %d", ulObjId, lpRights->__ptr[i].ulUserid, lpRights->__ptr[i].ulType, lpRights->__ptr[i].ulRights);
  943. }
  944. scoped_rlock lock(m_hCacheMutex);
  945. return m_AclCache.AddCacheItem(ulObjId, sACLs);
  946. }
  947. ECRESULT ECCacheManager::_DelACLs(unsigned int ulObjId)
  948. {
  949. scoped_rlock lock(m_hCacheMutex);
  950. LOG_USERCACHE_DEBUG("Remove ACLs for objectid %d", ulObjId);
  951. return m_AclCache.RemoveCacheItem(ulObjId);
  952. }
  953. ECRESULT ECCacheManager::GetQuota(unsigned int ulUserId, bool bIsDefaultQuota, quotadetails_t *quota)
  954. {
  955. // Try cache first
  956. return _GetQuota(ulUserId, bIsDefaultQuota, quota);
  957. // on error, ECSecurity will update the cache
  958. }
  959. ECRESULT ECCacheManager::SetQuota(unsigned int ulUserId, bool bIsDefaultQuota,
  960. const quotadetails_t &quota)
  961. {
  962. ECRESULT er = erSuccess;
  963. ECsQuota sQuota;
  964. sQuota.quota = quota;
  965. scoped_rlock lock(m_hCacheMutex);
  966. if (bIsDefaultQuota)
  967. er = m_QuotaUserDefaultCache.AddCacheItem(ulUserId, sQuota);
  968. else
  969. er = m_QuotaCache.AddCacheItem(ulUserId, sQuota);
  970. return er;
  971. }
  972. ECRESULT ECCacheManager::_GetQuota(unsigned int ulUserId, bool bIsDefaultQuota, quotadetails_t *quota)
  973. {
  974. ECRESULT er;
  975. ECsQuota *sQuota;
  976. scoped_rlock lock(m_hCacheMutex);
  977. if (quota == NULL)
  978. return KCERR_INVALID_PARAMETER;
  979. if (bIsDefaultQuota)
  980. er = m_QuotaUserDefaultCache.GetCacheItem(ulUserId, &sQuota);
  981. else
  982. er = m_QuotaCache.GetCacheItem(ulUserId, &sQuota);
  983. if(er != erSuccess)
  984. return er;
  985. *quota = sQuota->quota;
  986. return erSuccess;
  987. }
  988. ECRESULT ECCacheManager::_DelQuota(unsigned int ulUserId, bool bIsDefaultQuota)
  989. {
  990. ECRESULT er = erSuccess;
  991. scoped_rlock lock(m_hCacheMutex);
  992. if (bIsDefaultQuota)
  993. er = m_QuotaUserDefaultCache.RemoveCacheItem(ulUserId);
  994. else
  995. er = m_QuotaCache.RemoveCacheItem(ulUserId);
  996. return er;
  997. }
  998. void ECCacheManager::ForEachCacheItem(void(callback)(const std::string &, const std::string &, const std::string &, void*), void *obj)
  999. {
  1000. ulock_rec l_cache(m_hCacheMutex);
  1001. m_ObjectsCache.RequestStats(callback, obj);
  1002. m_StoresCache.RequestStats(callback, obj);
  1003. m_AclCache.RequestStats(callback, obj);
  1004. m_QuotaCache.RequestStats(callback, obj);
  1005. m_QuotaUserDefaultCache.RequestStats( callback, obj);
  1006. m_UEIdObjectCache.RequestStats(callback, obj);
  1007. m_UserObjectCache.RequestStats(callback, obj);
  1008. m_UserObjectDetailsCache.RequestStats(callback, obj);
  1009. m_ServerDetailsCache.RequestStats(callback, obj);
  1010. l_cache.unlock();
  1011. ulock_rec l_cell(m_hCacheCellsMutex);
  1012. m_CellCache.RequestStats(callback, obj);
  1013. l_cell.unlock();
  1014. ulock_rec l_prop(m_hCacheIndPropMutex);
  1015. m_PropToObjectCache.RequestStats(callback, obj);
  1016. m_ObjectToPropCache.RequestStats(callback, obj);
  1017. l_prop.unlock();
  1018. }
  1019. ECRESULT ECCacheManager::DumpStats()
  1020. {
  1021. ec_log_info("Dumping cache stats:");
  1022. ulock_rec l_cache(m_hCacheMutex);
  1023. m_ObjectsCache.DumpStats();
  1024. m_StoresCache.DumpStats();
  1025. m_AclCache.DumpStats();
  1026. m_QuotaCache.DumpStats();
  1027. m_QuotaUserDefaultCache.DumpStats();
  1028. m_UEIdObjectCache.DumpStats();
  1029. m_UserObjectCache.DumpStats();
  1030. m_UserObjectDetailsCache.DumpStats();
  1031. m_ServerDetailsCache.DumpStats();
  1032. l_cache.unlock();
  1033. ulock_rec l_cells(m_hCacheCellsMutex);
  1034. m_CellCache.DumpStats();
  1035. l_cells.unlock();
  1036. ulock_rec l_prop(m_hCacheIndPropMutex);
  1037. m_PropToObjectCache.DumpStats();
  1038. m_ObjectToPropCache.DumpStats();
  1039. l_prop.unlock();
  1040. return erSuccess;
  1041. }
  1042. ECRESULT ECCacheManager::GetObjectFlags(unsigned int ulObjId, unsigned int *ulFlags)
  1043. {
  1044. return GetObject(ulObjId, NULL, NULL, ulFlags);
  1045. }
  1046. ECRESULT ECCacheManager::GetCell(const sObjectTableKey *lpsRowItem,
  1047. unsigned int ulPropTag, struct propVal *lpDest, struct soap *soap,
  1048. bool bComputed)
  1049. {
  1050. ECRESULT er = erSuccess;
  1051. ECsCells *sCell;
  1052. scoped_rlock lock(m_hCacheCellsMutex);
  1053. if (m_bCellCacheDisabled) {
  1054. er = KCERR_NOT_FOUND;
  1055. goto exit;
  1056. }
  1057. // only support caching order id 0 (non-multi-valued)
  1058. if(lpsRowItem->ulOrderId != 0) {
  1059. er = KCERR_NOT_FOUND;
  1060. goto exit;
  1061. }
  1062. er = m_CellCache.GetCacheItem(lpsRowItem->ulObjId, &sCell);
  1063. if(er != erSuccess)
  1064. goto exit;
  1065. if(!sCell->GetPropVal(ulPropTag, lpDest, soap)) {
  1066. if(!sCell->GetComplete() || bComputed) {
  1067. // Object is not complete, and item is not in cache. We simply don't know anything about
  1068. // the item, so return NOT_FOUND. Or, the item is complete but the requested property is computed, and therefore
  1069. // not in the cache.
  1070. m_CellCache.DecrementValidCount();
  1071. er = KCERR_NOT_FOUND;
  1072. goto exit;
  1073. } else {
  1074. // Object is complete and property is not found; we know that the property does not exist
  1075. // so return OK with a NOT_FOUND propvalue
  1076. lpDest->ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulPropTag));
  1077. lpDest->Value.ul = KCERR_NOT_FOUND;
  1078. lpDest->__union = SOAP_UNION_propValData_ul;
  1079. }
  1080. }
  1081. exit:
  1082. if (er != erSuccess)
  1083. LOG_CELLCACHE_DEBUG("Get cell object %d tag 0x%08X item not found", lpsRowItem->ulObjId, ulPropTag);
  1084. else
  1085. LOG_CELLCACHE_DEBUG("Get cell object %d tag 0x%08X result found", lpsRowItem->ulObjId, ulPropTag);
  1086. return er;
  1087. }
  1088. ECRESULT ECCacheManager::SetCell(const sObjectTableKey *lpsRowItem,
  1089. unsigned int ulPropTag, const struct propVal *lpSrc)
  1090. {
  1091. ECRESULT er = erSuccess;
  1092. ECsCells *sCell;
  1093. if (lpsRowItem->ulOrderId != 0)
  1094. return KCERR_NOT_FOUND;
  1095. scoped_rlock lock(m_hCacheCellsMutex);
  1096. if (m_CellCache.GetCacheItem(lpsRowItem->ulObjId, &sCell) == erSuccess) {
  1097. long long ulSize = sCell->GetSize();
  1098. sCell->AddPropVal(ulPropTag, lpSrc);
  1099. ulSize -= sCell->GetSize();
  1100. // ulSize is positive if the cache shrank
  1101. //m_ulCellSize -= ulSize;
  1102. m_CellCache.AddToSize(-ulSize);
  1103. } else {
  1104. ECsCells sNewCell;
  1105. sNewCell.AddPropVal(ulPropTag, lpSrc);
  1106. er = m_CellCache.AddCacheItem(lpsRowItem->ulObjId, sNewCell);
  1107. if(er != erSuccess)
  1108. goto exit;
  1109. }
  1110. exit:
  1111. if (er != erSuccess)
  1112. LOG_CELLCACHE_DEBUG("Set cell object %d tag 0x%08X error 0x%08X", lpsRowItem->ulObjId, ulPropTag, er);
  1113. else
  1114. LOG_CELLCACHE_DEBUG("Set cell object %d tag 0x%08X", lpsRowItem->ulObjId, ulPropTag);
  1115. return er;
  1116. }
  1117. ECRESULT ECCacheManager::SetComplete(unsigned int ulObjId)
  1118. {
  1119. ECRESULT er = erSuccess;
  1120. ECsCells *sCell;
  1121. scoped_rlock lock(m_hCacheCellsMutex);
  1122. if (m_CellCache.GetCacheItem(ulObjId, &sCell) == erSuccess) {
  1123. sCell->SetComplete(true);
  1124. } else {
  1125. er = KCERR_NOT_FOUND;
  1126. goto exit;
  1127. }
  1128. exit:
  1129. if (er != erSuccess)
  1130. LOG_CELLCACHE_DEBUG("Set cell complete for object %d failed cell not found", ulObjId);
  1131. else
  1132. LOG_CELLCACHE_DEBUG("Set cell complete for object %d", ulObjId);
  1133. return er;
  1134. }
  1135. ECRESULT ECCacheManager::UpdateCell(unsigned int ulObjId, unsigned int ulPropTag, int lDelta)
  1136. {
  1137. ECRESULT er = erSuccess;
  1138. ECsCells *sCell;
  1139. scoped_rlock lock(m_hCacheCellsMutex);
  1140. if (m_CellCache.GetCacheItem(ulObjId, &sCell) == erSuccess) {
  1141. sCell->UpdatePropVal(ulPropTag, lDelta);
  1142. } else {
  1143. er = KCERR_NOT_FOUND;
  1144. goto exit;
  1145. }
  1146. exit:
  1147. if (er != erSuccess)
  1148. LOG_CELLCACHE_DEBUG("Update cell object %d tag 0x%08X, delta %d failed cell not found", ulObjId, ulPropTag, lDelta);
  1149. else
  1150. LOG_CELLCACHE_DEBUG("Update cell object %d tag 0x%08X, delta %d", ulObjId, ulPropTag, lDelta);
  1151. return er;
  1152. }
  1153. ECRESULT ECCacheManager::UpdateCell(unsigned int ulObjId, unsigned int ulPropTag, unsigned int ulMask, unsigned int ulValue)
  1154. {
  1155. ECRESULT er = erSuccess;
  1156. ECsCells *sCell;
  1157. scoped_rlock lock(m_hCacheCellsMutex);
  1158. if (m_CellCache.GetCacheItem(ulObjId, &sCell) == erSuccess) {
  1159. sCell->UpdatePropVal(ulPropTag, ulMask, ulValue);
  1160. } else {
  1161. er = KCERR_NOT_FOUND;
  1162. goto exit;
  1163. }
  1164. exit:
  1165. if (er != erSuccess)
  1166. LOG_CELLCACHE_DEBUG("Update cell object %d tag 0x%08X, mask 0x%08X, value %d failed cell not found", ulObjId, ulPropTag, ulMask, ulValue);
  1167. else
  1168. LOG_CELLCACHE_DEBUG("Update cell object %d tag 0x%08X, mask 0x%08X, value %d", ulObjId, ulPropTag, ulMask, ulValue);
  1169. return er;
  1170. }
  1171. ECRESULT ECCacheManager::_DelCell(unsigned int ulObjId)
  1172. {
  1173. scoped_rlock lock(m_hCacheCellsMutex);
  1174. return m_CellCache.RemoveCacheItem(ulObjId);
  1175. }
  1176. ECRESULT ECCacheManager::GetServerDetails(const std::string &strServerId, serverdetails_t *lpsDetails)
  1177. {
  1178. ECsServerDetails *sEntry;
  1179. scoped_rlock lock(m_hCacheMutex);
  1180. ECRESULT er = m_ServerDetailsCache.GetCacheItem(strToLower(strServerId), &sEntry);
  1181. if (er != erSuccess)
  1182. return er;
  1183. if (lpsDetails)
  1184. *lpsDetails = sEntry->sDetails;
  1185. return er;
  1186. }
  1187. ECRESULT ECCacheManager::SetServerDetails(const std::string &strServerId, const serverdetails_t &sDetails)
  1188. {
  1189. ECsServerDetails sEntry;
  1190. sEntry.sDetails = sDetails;
  1191. scoped_rlock lock(m_hCacheMutex);
  1192. return m_ServerDetailsCache.AddCacheItem(strToLower(strServerId), sEntry);
  1193. }
  1194. ECRESULT ECCacheManager::RemoveIndexData(unsigned int ulObjId)
  1195. {
  1196. ECRESULT er = erSuccess;
  1197. ECsIndexObject sObjectKeyLower, sObjectKeyUpper;
  1198. std::list<ECMapObjectToProp::value_type> lstItems;
  1199. // Get all records with specified hierarchyid and all tags (0 -> 0xffffffff)
  1200. sObjectKeyLower.ulObjId = ulObjId;
  1201. sObjectKeyLower.ulTag = 0;
  1202. sObjectKeyUpper.ulObjId = ulObjId;
  1203. sObjectKeyUpper.ulTag = 0xffffffff;
  1204. scoped_rlock lock(m_hCacheIndPropMutex);
  1205. er = m_ObjectToPropCache.GetCacheRange(sObjectKeyLower, sObjectKeyUpper, &lstItems);
  1206. for (const auto &p : lstItems) {
  1207. m_ObjectToPropCache.RemoveCacheItem(p.first);
  1208. m_PropToObjectCache.RemoveCacheItem(p.second);
  1209. }
  1210. return er;
  1211. }
  1212. ECRESULT ECCacheManager::RemoveIndexData(unsigned int ulPropTag, unsigned int cbData, unsigned char *lpData)
  1213. {
  1214. ECsIndexProp sObject;
  1215. ECsIndexObject *sObjectId;
  1216. if (lpData == NULL || cbData == 0)
  1217. return KCERR_INVALID_PARAMETER;
  1218. LOG_CACHE_DEBUG("Remove indexdata proptag 0x%08X, data %s", ulPropTag, bin2hex(cbData, lpData).c_str());
  1219. sObject.ulTag = PROP_ID(ulPropTag);
  1220. sObject.cbData = cbData;
  1221. sObject.lpData = lpData; // Cheap copy, Set this item on NULL before you exit
  1222. {
  1223. scoped_rlock lock(m_hCacheIndPropMutex);
  1224. if(m_PropToObjectCache.GetCacheItem(sObject, &sObjectId) == erSuccess) {
  1225. m_ObjectToPropCache.RemoveCacheItem(*sObjectId);
  1226. m_PropToObjectCache.RemoveCacheItem(sObject);
  1227. }
  1228. }
  1229. // Make sure there's no delete when it goes out of scope
  1230. sObject.lpData = NULL;
  1231. return erSuccess;
  1232. }
  1233. ECRESULT ECCacheManager::RemoveIndexData(unsigned int ulPropTag, unsigned int ulObjId)
  1234. {
  1235. ECRESULT er = erSuccess;
  1236. ECsIndexObject sObject;
  1237. ECsIndexProp *sObjectId;
  1238. sObject.ulTag = PROP_ID(ulPropTag);
  1239. sObject.ulObjId = ulObjId;
  1240. LOG_CACHE_DEBUG("Remove index data proptag 0x%08X, objectid %d", ulPropTag, ulObjId);
  1241. {
  1242. scoped_rlock lock(m_hCacheIndPropMutex);
  1243. if(m_ObjectToPropCache.GetCacheItem(sObject, &sObjectId) == erSuccess) {
  1244. m_PropToObjectCache.RemoveCacheItem(*sObjectId);
  1245. m_ObjectToPropCache.RemoveCacheItem(sObject);
  1246. }
  1247. }
  1248. return er;
  1249. }
  1250. ECRESULT ECCacheManager::_AddIndexData(const ECsIndexObject *lpObject,
  1251. const ECsIndexProp *lpProp)
  1252. {
  1253. ECRESULT er;
  1254. scoped_rlock lock(m_hCacheIndPropMutex);
  1255. // Remove any pre-existing references to this data
  1256. RemoveIndexData(PROP_TAG(PT_UNSPECIFIED, lpObject->ulTag), lpObject->ulObjId);
  1257. RemoveIndexData(PROP_TAG(PT_UNSPECIFIED, lpProp->ulTag), lpProp->cbData, lpProp->lpData);
  1258. er = m_PropToObjectCache.AddCacheItem(*lpProp, *lpObject);
  1259. if(er != erSuccess)
  1260. return er;
  1261. er = m_ObjectToPropCache.AddCacheItem(*lpObject, *lpProp);
  1262. if(er != erSuccess)
  1263. return er;
  1264. return erSuccess;
  1265. }
  1266. ECRESULT ECCacheManager::GetPropFromObject(unsigned int ulTag, unsigned int ulObjId, struct soap *soap, unsigned int* lpcbData, unsigned char** lppData)
  1267. {
  1268. ECRESULT er = erSuccess;
  1269. DB_RESULT lpDBResult;
  1270. DB_ROW lpDBRow = NULL;
  1271. DB_LENGTHS lpDBLenths = NULL;
  1272. std::string strQuery;
  1273. ECDatabase* lpDatabase = NULL;
  1274. ECsIndexProp *sObject = NULL;
  1275. ECsIndexObject sObjectKey;
  1276. ECsIndexProp sNewObject;
  1277. sObjectKey.ulObjId = ulObjId;
  1278. sObjectKey.ulTag = ulTag;
  1279. LOG_CACHE_DEBUG("Get Prop From Object tag=0x%04X, objectid %d", ulTag, ulObjId);
  1280. {
  1281. scoped_rlock lock(m_hCacheIndPropMutex);
  1282. er = m_ObjectToPropCache.GetCacheItem(sObjectKey, &sObject);
  1283. if(er == erSuccess) {
  1284. *lppData = s_alloc<unsigned char>(soap, sObject->cbData);
  1285. *lpcbData = sObject->cbData;
  1286. memcpy(*lppData, sObject->lpData, sObject->cbData);
  1287. // All done
  1288. goto exit;
  1289. }
  1290. }
  1291. // item not found, search in the database
  1292. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  1293. if(er != erSuccess)
  1294. goto exit;
  1295. // Get them from the database
  1296. strQuery = "SELECT val_binary FROM indexedproperties FORCE INDEX(PRIMARY) WHERE tag="+stringify(ulTag)+" AND hierarchyid="+stringify(ulObjId) + " LIMIT 1";
  1297. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  1298. if(er != erSuccess)
  1299. goto exit;
  1300. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  1301. lpDBLenths = lpDatabase->FetchRowLengths(lpDBResult);
  1302. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBLenths == NULL) {
  1303. er = KCERR_NOT_FOUND;
  1304. goto exit;
  1305. }
  1306. sNewObject.SetValue(ulTag, (unsigned char*) lpDBRow[0], (unsigned int) lpDBLenths[0]);
  1307. er = _AddIndexData(&sObjectKey, &sNewObject);
  1308. if(er != erSuccess)
  1309. goto exit;
  1310. sObject = &sNewObject;
  1311. *lppData = s_alloc<unsigned char>(soap, sObject->cbData);
  1312. *lpcbData = sObject->cbData;
  1313. memcpy(*lppData, sObject->lpData, sObject->cbData);
  1314. exit:
  1315. if (er != erSuccess || sObject == NULL)
  1316. LOG_CACHE_DEBUG("Get Prop From Object tag=0x%04X, objectid %d, error 0x%08x", ulTag, ulObjId, er);
  1317. else
  1318. LOG_CACHE_DEBUG("Get Prop From Object tag=0x%04X, objectid %d, data %s", ulTag, ulObjId, bin2hex(sObject->cbData, sObject->lpData).c_str());
  1319. return er;
  1320. }
  1321. ECRESULT ECCacheManager::GetObjectFromProp(unsigned int ulTag, unsigned int cbData, unsigned char* lpData, unsigned int* lpulObjId)
  1322. {
  1323. ECRESULT er = erSuccess;
  1324. DB_RESULT lpDBResult;
  1325. DB_ROW lpDBRow = NULL;
  1326. std::string strQuery;
  1327. ECDatabase* lpDatabase = NULL;
  1328. ECsIndexObject sNewIndexObject;
  1329. ECsIndexProp sObject;
  1330. bool bCacheResult = false;
  1331. if(lpData == NULL || lpulObjId == NULL || cbData == 0) {
  1332. er = KCERR_INVALID_PARAMETER;
  1333. goto exit;
  1334. }
  1335. if(QueryObjectFromProp(ulTag, cbData, lpData, lpulObjId) == erSuccess) {
  1336. bCacheResult = true;
  1337. goto exit;
  1338. }
  1339. // Item not found, search in database
  1340. er = GetThreadLocalDatabase(this->m_lpDatabaseFactory, &lpDatabase);
  1341. if(er != erSuccess)
  1342. goto exit;
  1343. // Get them from the database
  1344. strQuery = "SELECT hierarchyid FROM indexedproperties FORCE INDEX(bin) WHERE tag="+stringify(ulTag)+" AND val_binary="+ lpDatabase->EscapeBinary(lpData, cbData) + " LIMIT 1";
  1345. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  1346. if(er != erSuccess)
  1347. goto exit;
  1348. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  1349. if(lpDBRow == NULL || lpDBRow[0] == NULL) {
  1350. er = KCERR_NOT_FOUND;
  1351. goto exit;
  1352. }
  1353. sNewIndexObject.ulTag = ulTag;
  1354. sNewIndexObject.ulObjId = atoui(lpDBRow[0]);
  1355. sObject.ulTag = ulTag;
  1356. sObject.cbData = cbData;
  1357. sObject.lpData = lpData; // Cheap copy, Set this item on NULL before you exit
  1358. er = _AddIndexData(&sNewIndexObject, &sObject);
  1359. if (er != erSuccess)
  1360. goto exit;
  1361. *lpulObjId = sNewIndexObject.ulObjId;
  1362. exit:
  1363. sObject.lpData = NULL; // Remove reference
  1364. if (er != erSuccess)
  1365. LOG_CACHE_DEBUG("Get object from prop tag 0x%04X, data %s error 0x%08x", ulTag, bin2hex(cbData, lpData).c_str(), er);
  1366. else
  1367. LOG_CACHE_DEBUG("Get object from prop tag 0x%04X, data %s result [%s]: objectid %d", ulTag, bin2hex(cbData, lpData).c_str(), ((bCacheResult)?"C":"D"), *lpulObjId);
  1368. return er;
  1369. }
  1370. ECRESULT ECCacheManager::QueryObjectFromProp(unsigned int ulTag, unsigned int cbData, unsigned char* lpData, unsigned int* lpulObjId)
  1371. {
  1372. ECRESULT er = erSuccess;
  1373. ECsIndexProp sObject;
  1374. ECsIndexObject *sIndexObject;
  1375. if(lpData == NULL || lpulObjId == NULL || cbData == 0) {
  1376. er = KCERR_INVALID_PARAMETER;
  1377. goto exit;
  1378. }
  1379. sObject.ulTag = ulTag;
  1380. sObject.cbData = cbData;
  1381. sObject.lpData = lpData; // Cheap copy, Set this item on NULL before you exit
  1382. {
  1383. scoped_rlock lock(m_hCacheIndPropMutex);
  1384. er = m_PropToObjectCache.GetCacheItem(sObject, &sIndexObject);
  1385. if(er != erSuccess)
  1386. goto exit;
  1387. *lpulObjId = sIndexObject->ulObjId;
  1388. }
  1389. exit:
  1390. sObject.lpData = NULL;
  1391. return er;
  1392. }
  1393. ECRESULT ECCacheManager::SetObjectProp(unsigned int ulTag, unsigned int cbData, unsigned char *lpData, unsigned int ulObjId)
  1394. {
  1395. ECRESULT er = erSuccess;
  1396. ECsIndexObject sObject;
  1397. ECsIndexProp sProp;
  1398. sObject.ulTag = ulTag;
  1399. sObject.ulObjId = ulObjId;
  1400. sProp.SetValue(ulTag, lpData, cbData);
  1401. er = _AddIndexData(&sObject, &sProp);
  1402. LOG_CACHE_DEBUG("Set object prop tag 0x%04X, data %s, objectid %d", ulTag, bin2hex(cbData, lpData).c_str(), ulObjId);
  1403. return er;
  1404. }
  1405. ECRESULT ECCacheManager::GetEntryIdFromObject(unsigned int ulObjId, struct soap *soap, unsigned int ulFlags, entryId** lppEntryId)
  1406. {
  1407. ECRESULT er = erSuccess;
  1408. entryId* lpEntryId = s_alloc<entryId>(soap);
  1409. er = GetEntryIdFromObject(ulObjId, soap, ulFlags, lpEntryId);
  1410. if (er != erSuccess)
  1411. goto exit;
  1412. // Flags already set by GetEntryIdFromObject(4args)
  1413. *lppEntryId = lpEntryId;
  1414. exit:
  1415. if (er != erSuccess)
  1416. s_free(nullptr, lpEntryId);
  1417. return er;
  1418. }
  1419. ECRESULT ECCacheManager::GetEntryIdFromObject(unsigned int ulObjId, struct soap *soap, unsigned int ulFlags, entryId* lpEntryId)
  1420. {
  1421. ECRESULT er;
  1422. er = GetPropFromObject( PROP_ID(PR_ENTRYID), ulObjId, soap, (unsigned int*)&lpEntryId->__size, &lpEntryId->__ptr);
  1423. if (er != erSuccess)
  1424. return er;
  1425. // Set flags in entryid
  1426. static_assert(offsetof(EID, usFlags) == offsetof(EID_V0, usFlags),
  1427. "usFlags member not at same position");
  1428. auto d = reinterpret_cast<EID *>(lpEntryId->__ptr);
  1429. if (lpEntryId->__size < 0 ||
  1430. static_cast<size_t>(lpEntryId->__size) <
  1431. offsetof(EID, usFlags) + sizeof(d->usFlags)) {
  1432. ec_log_err("K-1572: %s: entryid has size %d; not enough for EID_V1.usFlags (%zu)",
  1433. __func__, lpEntryId->__size, offsetof(EID, usFlags) + sizeof(d->usFlags));
  1434. return MAPI_E_CORRUPT_DATA;
  1435. }
  1436. d->usFlags = ulFlags;
  1437. return erSuccess;
  1438. }
  1439. ECRESULT ECCacheManager::GetObjectFromEntryId(const entryId *lpEntryId,
  1440. unsigned int *lpulObjId)
  1441. {
  1442. // Make sure flags is 0 when getting from db/cache
  1443. if (lpEntryId == nullptr)
  1444. ec_log_err("K-1575: null entryid passed to %s", __func__);
  1445. EntryId eid(lpEntryId);
  1446. try {
  1447. eid.setFlags(0);
  1448. } catch (runtime_error &e) {
  1449. ec_log_err("K-1573: eid.setFlags: %s\n", e.what());
  1450. /*
  1451. * The subsequent functions will catch the too-small eid.size
  1452. * and return INVALID_PARAM appropriately.
  1453. */
  1454. }
  1455. return GetObjectFromProp(PROP_ID(PR_ENTRYID), eid.size(), eid, lpulObjId);
  1456. }
  1457. ECRESULT ECCacheManager::SetObjectEntryId(const entryId *lpEntryId,
  1458. unsigned int ulObjId)
  1459. {
  1460. ECRESULT er = erSuccess;
  1461. // MAke sure flags is 0 when saving in DB
  1462. if (lpEntryId == nullptr)
  1463. ec_log_err("K-1576: null entryid passed to %s", __func__);
  1464. EntryId eid(lpEntryId);
  1465. try {
  1466. eid.setFlags(0);
  1467. } catch (runtime_error &e) {
  1468. ec_log_err("K-1574: eid.setFlags: %s\n", e.what());
  1469. /* ignore exception - the following functions will catch the too-small eid.size */
  1470. }
  1471. er = SetObjectProp( PROP_ID(PR_ENTRYID), eid.size(), eid, ulObjId);
  1472. return er;
  1473. }
  1474. /**
  1475. * Convert entryid to database object id
  1476. */
  1477. ECRESULT ECCacheManager::GetEntryListToObjectList(struct entryList *lpEntryList, ECListInt* lplObjectList)
  1478. {
  1479. ECRESULT er = erSuccess;
  1480. unsigned int ulId = 0;
  1481. bool bPartialCompletion = false;
  1482. if(lpEntryList == NULL) {
  1483. er = KCERR_INVALID_PARAMETER;
  1484. goto exit;
  1485. }
  1486. for (unsigned int i = 0; i < lpEntryList->__size; ++i) {
  1487. if(GetObjectFromEntryId(&lpEntryList->__ptr[i], &ulId) != erSuccess) {
  1488. bPartialCompletion = true;
  1489. continue; // Unknown entryid, next item
  1490. }
  1491. lplObjectList->push_back(ulId);
  1492. }
  1493. exit:
  1494. if(bPartialCompletion)
  1495. er = KCWARN_PARTIAL_COMPLETION;
  1496. return er;
  1497. }
  1498. /**
  1499. * Convert database object id to entryid
  1500. */
  1501. ECRESULT ECCacheManager::GetEntryListFromObjectList(ECListInt* lplObjectList, struct soap *soap, struct entryList **lppEntryList)
  1502. {
  1503. ECRESULT er = erSuccess;
  1504. bool bPartialCompletion = false;
  1505. entryList* lpEntryList = s_alloc<entryList>(soap);
  1506. if(lplObjectList == NULL || lppEntryList == NULL) {
  1507. er = KCERR_INVALID_PARAMETER;
  1508. goto exit;
  1509. }
  1510. lpEntryList->__ptr = s_alloc<entryId>(soap, lplObjectList->size());
  1511. lpEntryList->__size = 0;
  1512. for (auto xint : *lplObjectList) {
  1513. if (GetEntryIdFromObject(xint, soap, 0, &lpEntryList->__ptr[lpEntryList->__size]) != erSuccess) {
  1514. bPartialCompletion = true;
  1515. continue; // Unknown entryid, next item
  1516. }
  1517. ++lpEntryList->__size;
  1518. }
  1519. *lppEntryList = lpEntryList;
  1520. exit:
  1521. if (er != erSuccess && lpEntryList)
  1522. FreeEntryList(lpEntryList, true);
  1523. if(bPartialCompletion)
  1524. er = KCWARN_PARTIAL_COMPLETION;
  1525. return er;
  1526. }
  1527. /**
  1528. * Get list of indexed properties for the indexer
  1529. *
  1530. * This is not a read-through, the data must be set via SetIndexedProperties
  1531. *
  1532. * @param[out] map Map of property ID -> text name
  1533. * @return Result
  1534. */
  1535. ECRESULT ECCacheManager::GetExcludedIndexProperties(std::set<unsigned int>& set)
  1536. {
  1537. scoped_lock lock(m_hExcludedIndexPropertiesMutex);
  1538. if (m_setExcludedIndexProperties.empty())
  1539. return KCERR_NOT_FOUND;
  1540. set = m_setExcludedIndexProperties;
  1541. return erSuccess;
  1542. }
  1543. /**
  1544. * Set list of indexed properties for the indexer
  1545. *
  1546. * @param[in] map Map of property ID -> text name
  1547. * @return result
  1548. */
  1549. ECRESULT ECCacheManager::SetExcludedIndexProperties(const std::set<unsigned int> &set)
  1550. {
  1551. scoped_lock lock(m_hExcludedIndexPropertiesMutex);
  1552. m_setExcludedIndexProperties = set;
  1553. return erSuccess;
  1554. }
  1555. void ECCacheManager::DisableCellCache()
  1556. {
  1557. LOG_CELLCACHE_DEBUG("%s", "Disable cell cache");
  1558. m_bCellCacheDisabled = true;
  1559. }
  1560. void ECCacheManager::EnableCellCache()
  1561. {
  1562. LOG_CELLCACHE_DEBUG("%s", "Enable cell cache");
  1563. m_bCellCacheDisabled = false;
  1564. }
  1565. } /* namespace */