Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

756 lines
16 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 2000-2001 by Microsoft Corp. All Rights Reserved.
  4. //
  5. // INDEX.CPP
  6. //
  7. // 24-Oct-00 raymcc Integration layer to disk-based B-Tree
  8. //
  9. //***************************************************************************
  10. #include <wbemcomn.h>
  11. #include <reposit.h>
  12. #include "a51tools.h"
  13. #include "index.h"
  14. #include "btr.h"
  15. //***************************************************************************
  16. //
  17. //***************************************************************************
  18. //
  19. //#define DEBUG
  20. static CLockableFlexArray g_aIterators;
  21. class CIteratorBatch
  22. {
  23. CFlexArray m_aStrings;
  24. BOOL m_bDone;
  25. DWORD m_dwCursor;
  26. public:
  27. CIteratorBatch();
  28. ~CIteratorBatch();
  29. BOOL Purge(LPSTR pszTarget);
  30. BOOL Add(LPSTR pszSrc); // Acquires memory
  31. void SetDone() { m_bDone = TRUE; }
  32. BOOL Next(LPSTR *pString);
  33. static DWORD PurgeAll(LPSTR pszDoomed);
  34. };
  35. //***************************************************************************
  36. //
  37. // CIteratorBatch::PurgeAll
  38. //
  39. //
  40. // Purges all iterators of a particular string. This happens when
  41. // a DeleteKey succeeds while there are outstanding enumerators; we want
  42. // to remove the key from all enumerators so that deleted objects
  43. // are not reported.
  44. //
  45. // This is required because the enumerators do "prefetch" and may
  46. // have been invoked considerably in advance of the delete
  47. //
  48. // Assumes prior concurrency control.
  49. //
  50. //***************************************************************************
  51. // ok
  52. DWORD CIteratorBatch::PurgeAll(LPSTR pszDoomed)
  53. {
  54. DWORD dwTotal = 0;
  55. g_aIterators.Lock();
  56. for (int i = 0; i < g_aIterators.Size(); i++)
  57. {
  58. CIteratorBatch *p = (CIteratorBatch *) g_aIterators[i];
  59. BOOL bRes = p->Purge(pszDoomed);
  60. if (bRes)
  61. dwTotal++;
  62. }
  63. g_aIterators.Unlock();
  64. return dwTotal;
  65. }
  66. //***************************************************************************
  67. //
  68. // CIteratorBatch::CIteratorBatch
  69. //
  70. //***************************************************************************
  71. // ok
  72. CIteratorBatch::CIteratorBatch()
  73. {
  74. m_bDone = FALSE;
  75. m_dwCursor = 0;
  76. g_aIterators.Lock();
  77. g_aIterators.Add(this);
  78. g_aIterators.Unlock();
  79. }
  80. //***************************************************************************
  81. //
  82. // CIteratorBatch::Add
  83. //
  84. // Adds a string to the enumerator.
  85. //
  86. //***************************************************************************
  87. //
  88. BOOL CIteratorBatch::Add(LPSTR pszSrc)
  89. {
  90. int nRes = m_aStrings.Add(pszSrc);
  91. if (nRes)
  92. return FALSE;
  93. return TRUE;
  94. }
  95. //***************************************************************************
  96. //
  97. // CIteratorBatch::~CIteratorBatch
  98. //
  99. // Removes all remaining strings and deallocates them and removes
  100. // this iterator from the global list.
  101. //
  102. // Assumes prior concurrency control.
  103. //
  104. //***************************************************************************
  105. //
  106. CIteratorBatch::~CIteratorBatch()
  107. {
  108. for (int i = 0; i < m_aStrings.Size(); i++)
  109. {
  110. _BtrMemFree(m_aStrings[i]);
  111. }
  112. g_aIterators.Lock();
  113. for (i = 0; i < g_aIterators.Size(); i++)
  114. {
  115. if (g_aIterators[i] == this)
  116. {
  117. g_aIterators.RemoveAt(i);
  118. break;
  119. }
  120. }
  121. g_aIterators.Unlock();
  122. }
  123. //***************************************************************************
  124. //
  125. // CIteratorBatch::Purge
  126. //
  127. // Removes a specific string from the enumerator. Happens when a concurrent
  128. // delete succeeds; we have to remove the deleted key from the enumeration
  129. // for result set coherence.
  130. //
  131. // Assumes prior concurrency control.
  132. //
  133. // Returns FALSE if the string was not removed, TRUE if it was. The
  134. // return value is mostly a debugging aid.
  135. //
  136. //***************************************************************************
  137. // ok
  138. BOOL CIteratorBatch::Purge(
  139. LPSTR pszTarget
  140. )
  141. {
  142. int nSize = m_aStrings.Size();
  143. if (nSize == 0)
  144. return FALSE;
  145. // First, check the first/last strings against
  146. // the first character of the target. We can
  147. // avoid a lot of strcmp calls if the target
  148. // is lexcially outside the range of the contents of
  149. // the enumerator.
  150. // ==================================================
  151. LPSTR pszFirst = (LPSTR) m_aStrings[0];
  152. LPSTR pszLast = (LPSTR) m_aStrings[nSize-1];
  153. if (*pszTarget > *pszLast)
  154. return FALSE;
  155. if (*pszTarget < *pszFirst)
  156. return FALSE;
  157. // If here, there is a chance that we have the
  158. // string in the enumerator. Since all keys are
  159. // retrieved in lexical order, a simple binary
  160. // search is all we need.
  161. // =============================================
  162. int nPosition = 0;
  163. int l = 0, u = nSize - 1;
  164. while (l <= u)
  165. {
  166. int m = (l + u) / 2;
  167. // m is the current key to consider 0...n-1
  168. LPSTR pszCandidate = (LPSTR) m_aStrings[m];
  169. int nRes = strcmp(pszTarget, pszCandidate);
  170. // Decide which way to cut the array in half.
  171. // ==========================================
  172. if (nRes < 0)
  173. {
  174. u = m - 1;
  175. nPosition = u + 1;
  176. }
  177. else if (nRes > 0)
  178. {
  179. l = m + 1;
  180. nPosition = l;
  181. }
  182. else
  183. {
  184. // If here, we found the darn thing. Life is good.
  185. // Zap it and return!
  186. // ================================================
  187. _BtrMemFree(pszCandidate);
  188. m_aStrings.RemoveAt(m);
  189. return TRUE;
  190. }
  191. }
  192. return FALSE;
  193. }
  194. //***************************************************************************
  195. //
  196. // CIteratorBatch::Next
  197. //
  198. // Returns the next string from the enumeration prefetch.
  199. //
  200. //***************************************************************************
  201. //
  202. BOOL CIteratorBatch::Next(LPSTR *pMem)
  203. {
  204. if (m_aStrings.Size())
  205. {
  206. *pMem = (LPSTR) m_aStrings[0];
  207. m_aStrings.RemoveAt(0);
  208. return TRUE;
  209. }
  210. return FALSE;
  211. }
  212. //***************************************************************************
  213. //
  214. // CBtrIndex::CBtrIndex
  215. //
  216. //***************************************************************************
  217. //
  218. CBtrIndex::CBtrIndex()
  219. {
  220. m_dwPrefixLength = 0;
  221. }
  222. //***************************************************************************
  223. //
  224. // CBtrIndex::~CBtrIndex
  225. //
  226. //***************************************************************************
  227. //
  228. CBtrIndex::~CBtrIndex()
  229. {
  230. }
  231. long CBtrIndex::Shutdown(DWORD dwShutDownFlags)
  232. {
  233. long lRes;
  234. lRes = bt.Shutdown(dwShutDownFlags);
  235. if(lRes != ERROR_SUCCESS)
  236. return lRes;
  237. lRes = ps.Shutdown(dwShutDownFlags);
  238. if(lRes != ERROR_SUCCESS)
  239. return lRes;
  240. return ERROR_SUCCESS;
  241. }
  242. //***************************************************************************
  243. //
  244. // CBtrIndex::Initialize
  245. //
  246. //***************************************************************************
  247. //
  248. long CBtrIndex::Initialize(DWORD dwPrefixLength,
  249. LPCWSTR wszRepositoryDir,
  250. CPageSource* pSource)
  251. {
  252. // Initialize the files in question and map BTree into it.
  253. // =======================================================
  254. wchar_t buf[MAX_PATH];
  255. wcscpy(buf, wszRepositoryDir);
  256. wcscat(buf, L"\\index.btr");
  257. DWORD dwRes = ps.Init(8192, buf, pSource);
  258. dwRes |= bt.Init(&ps);
  259. m_dwPrefixLength = dwPrefixLength;
  260. return long(dwRes);
  261. }
  262. //***************************************************************************
  263. //
  264. // CBtrIndex::Create
  265. //
  266. //***************************************************************************
  267. //
  268. long CBtrIndex::Create(LPCWSTR wszFileName)
  269. {
  270. DWORD dwRes;
  271. if (wszFileName == 0)
  272. return ERROR_INVALID_PARAMETER;
  273. wszFileName += m_dwPrefixLength;
  274. // Convert to ANSI
  275. // ================
  276. char *pAnsi = new char[wcslen(wszFileName) + 1];
  277. if (pAnsi == 0)
  278. return ERROR_NOT_ENOUGH_MEMORY;
  279. LPCWSTR pSrc = wszFileName;
  280. char *pDest = pAnsi;
  281. while (*pSrc)
  282. *pDest++ = (char) *pSrc++;
  283. *pDest = 0;
  284. try
  285. {
  286. dwRes = bt.InsertKey(pAnsi, 0);
  287. }
  288. catch (...)
  289. {
  290. dwRes = ERROR_BADDB;
  291. }
  292. delete [] pAnsi;
  293. if (dwRes == ERROR_ALREADY_EXISTS)
  294. dwRes = NO_ERROR;
  295. return long(dwRes);
  296. }
  297. //***************************************************************************
  298. //
  299. // CBtrIndex::Delete
  300. //
  301. // Deletes a key from the index
  302. //
  303. //***************************************************************************
  304. //
  305. long CBtrIndex::Delete(LPCWSTR wszFileName)
  306. {
  307. DWORD dwRes = 0;
  308. wszFileName += m_dwPrefixLength;
  309. // Convert to ANSI
  310. // ================
  311. char *pAnsi = new char[wcslen(wszFileName) + 1];
  312. if (pAnsi == 0)
  313. return ERROR_NOT_ENOUGH_MEMORY;
  314. LPCWSTR pSrc = wszFileName;
  315. char *pDest = pAnsi;
  316. while (*pSrc)
  317. *pDest++ = (char) *pSrc++;
  318. *pDest = 0;
  319. try
  320. {
  321. dwRes = bt.DeleteKey(pAnsi);
  322. if (dwRes == 0)
  323. CIteratorBatch::PurgeAll(pAnsi);
  324. }
  325. catch (...)
  326. {
  327. dwRes = ERROR_BADDB;
  328. }
  329. delete pAnsi;
  330. return long(dwRes);
  331. }
  332. //***************************************************************************
  333. //
  334. // CBtrIndex::CopyStringToWIN32_FIND_DATA
  335. //
  336. // Does an ANSI to UNICODE convert for the key string.
  337. //
  338. //***************************************************************************
  339. //
  340. BOOL CBtrIndex::CopyStringToWIN32_FIND_DATA(
  341. LPSTR pszKey,
  342. LPWSTR pszDest
  343. )
  344. {
  345. LPSTR pszSuffix = pszKey + strlen(pszKey) - 1;
  346. while (pszSuffix[-1] != '\\' && pszSuffix > pszKey)
  347. {
  348. pszSuffix--;
  349. }
  350. // If here, a clean match.
  351. // =======================
  352. while (*pszSuffix)
  353. *pszDest++ = (wchar_t) *pszSuffix++;
  354. *pszDest = 0;
  355. return TRUE;
  356. }
  357. //***************************************************************************
  358. //
  359. // CBtrIndex::FindFirst
  360. //
  361. // Starts an enumeration
  362. //
  363. //***************************************************************************
  364. //
  365. long CBtrIndex::FindFirst(LPCWSTR wszPrefix, WIN32_FIND_DATAW* pfd,
  366. void** ppHandle)
  367. {
  368. DWORD dwRes;
  369. wszPrefix += m_dwPrefixLength;
  370. if(ppHandle)
  371. *ppHandle = INVALID_HANDLE_VALUE;
  372. pfd->cFileName[0] = 0;
  373. pfd->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  374. // Convert to ANSI
  375. // ================
  376. char *pAnsi = new char[wcslen(wszPrefix) + 1];
  377. if (pAnsi == 0)
  378. {
  379. return ERROR_NOT_ENOUGH_MEMORY;
  380. }
  381. CVectorDeleteMe<char> vdm(pAnsi);
  382. LPCWSTR pSrc = wszPrefix;
  383. char *pDest = pAnsi;
  384. while (*pSrc)
  385. *pDest++ = (char) *pSrc++;
  386. *pDest = 0;
  387. // Critical-section blocked.
  388. // =========================
  389. CBTreeIterator *pIt = new CBTreeIterator;
  390. if (!pIt)
  391. {
  392. return ERROR_NOT_ENOUGH_MEMORY;
  393. }
  394. try
  395. {
  396. dwRes = pIt->Init(&bt, pAnsi);
  397. }
  398. catch (...)
  399. {
  400. dwRes = ERROR_BADDB;
  401. }
  402. if (dwRes)
  403. {
  404. pIt->Release();
  405. return ERROR_FILE_NOT_FOUND;
  406. }
  407. // Create CIteratorBatch.
  408. // ======================
  409. CIteratorBatch *pBatch = new CIteratorBatch;
  410. if (pBatch == 0)
  411. {
  412. pIt->Release();
  413. return ERROR_NOT_ENOUGH_MEMORY;
  414. }
  415. // Iterate and fill batcher.
  416. // =========================
  417. LPSTR pszKey = 0;
  418. int nMatchLen = strlen(pAnsi);
  419. for (;;)
  420. {
  421. dwRes = pIt->Next(&pszKey);
  422. if (dwRes)
  423. break;
  424. // See if prefix matches.
  425. if (strncmp(pAnsi, pszKey, nMatchLen) != 0)
  426. {
  427. pIt->FreeString(pszKey);
  428. pBatch->SetDone();
  429. break;
  430. }
  431. pBatch->Add(pszKey);
  432. if (ppHandle == NULL)
  433. break; //Only asked for 1 item! No need to try the next
  434. }
  435. pIt->Release();
  436. long lRes = FindNext(pBatch, pfd);
  437. if (lRes == ERROR_NO_MORE_FILES)
  438. lRes = ERROR_FILE_NOT_FOUND;
  439. if (lRes == NO_ERROR)
  440. {
  441. if(ppHandle)
  442. {
  443. *ppHandle = (LPVOID *) pBatch;
  444. }
  445. else
  446. {
  447. //
  448. // Only asked for one --- close handle
  449. //
  450. delete pBatch;
  451. }
  452. }
  453. else
  454. {
  455. delete pBatch;
  456. }
  457. return lRes;
  458. }
  459. //***************************************************************************
  460. //
  461. // CBtrIndex::FindNext
  462. //
  463. // Continues an enumeration. Reads from the prefetch buffer.
  464. //
  465. //***************************************************************************
  466. //
  467. long CBtrIndex::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
  468. {
  469. LPSTR pszString = 0;
  470. BOOL bRes;
  471. if (pHandle == 0 || pfd == 0 || pHandle == INVALID_HANDLE_VALUE)
  472. return ERROR_INVALID_PARAMETER;
  473. CIteratorBatch *pBatch = (CIteratorBatch *) pHandle;
  474. bRes = pBatch->Next(&pszString);
  475. if (bRes == FALSE)
  476. return ERROR_NO_MORE_FILES;
  477. CopyStringToWIN32_FIND_DATA(pszString, pfd->cFileName);
  478. pfd->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  479. if (pszString)
  480. _BtrMemFree(pszString);
  481. return ERROR_SUCCESS;
  482. }
  483. //***************************************************************************
  484. //
  485. // CBtrIndex::FindClose
  486. //
  487. // Closes an enumeration by deleting the 'hidden' pointer.
  488. //
  489. //***************************************************************************
  490. // ok
  491. long CBtrIndex::FindClose(void* pHandle)
  492. {
  493. if (pHandle == 0 || pHandle == INVALID_HANDLE_VALUE)
  494. return NO_ERROR;
  495. delete (CIteratorBatch *) pHandle;
  496. return ERROR_SUCCESS;
  497. }
  498. long CBtrIndex::InvalidateCache()
  499. {
  500. //
  501. // Re-read the admin page from disk. NOTE: this will need changing if more
  502. // caching is added!
  503. //
  504. DWORD dwRes = ps.ReadAdminPage();
  505. if (dwRes == NO_ERROR)
  506. dwRes = bt.InvalidateCache();
  507. return long(dwRes);
  508. }
  509. long CBtrIndex::FlushCaches()
  510. {
  511. return bt.FlushCaches();
  512. }
  513. long CBtrIndex::IndexEnumerationBegin(const wchar_t *wszSearchPrefix, void **ppHandle)
  514. {
  515. DWORD dwRes = ERROR_SUCCESS;
  516. wszSearchPrefix += m_dwPrefixLength;
  517. if(ppHandle)
  518. *ppHandle = INVALID_HANDLE_VALUE;
  519. // Convert to ANSI
  520. // ================
  521. char *pAnsi = new char[wcslen(wszSearchPrefix) + 1];
  522. if (pAnsi == 0)
  523. {
  524. return ERROR_NOT_ENOUGH_MEMORY;
  525. }
  526. CVectorDeleteMe<char> vdm(pAnsi);
  527. LPCWSTR pSrc = wszSearchPrefix;
  528. char *pDest = pAnsi;
  529. while (*pSrc)
  530. *pDest++ = (char) *pSrc++;
  531. *pDest = 0;
  532. CBTreeIterator *pIt = new CBTreeIterator;
  533. if (!pIt)
  534. {
  535. return ERROR_NOT_ENOUGH_MEMORY;
  536. }
  537. try
  538. {
  539. dwRes = pIt->Init(&bt, pAnsi);
  540. }
  541. catch (...)
  542. {
  543. dwRes = ERROR_BADDB;
  544. }
  545. if (dwRes)
  546. {
  547. pIt->Release();
  548. return ERROR_FILE_NOT_FOUND;
  549. }
  550. // Create CIteratorBatch.
  551. // ======================
  552. CIteratorBatch *pBatch = new CIteratorBatch;
  553. if (pBatch == 0)
  554. {
  555. pIt->Release();
  556. return ERROR_NOT_ENOUGH_MEMORY;
  557. }
  558. // Iterate and fill batcher.
  559. // =========================
  560. LPSTR pszKey = 0;
  561. int nMatchLen = strlen(pAnsi);
  562. for (int nCount = 0;;nCount++)
  563. {
  564. dwRes = pIt->Next(&pszKey);
  565. if (dwRes == ERROR_NO_MORE_ITEMS)
  566. {
  567. //We hit the end of the BTree result set, so we need to ignore this error
  568. dwRes = 0;
  569. break;
  570. }
  571. if (dwRes)
  572. break;
  573. // See if prefix matches.
  574. if (strncmp(pAnsi, pszKey, nMatchLen) != 0)
  575. {
  576. pIt->FreeString(pszKey);
  577. pBatch->SetDone();
  578. break;
  579. }
  580. pBatch->Add(pszKey);
  581. }
  582. pIt->Release();
  583. if (nCount == 0)
  584. dwRes = ERROR_FILE_NOT_FOUND;
  585. if (dwRes == ERROR_SUCCESS)
  586. {
  587. if(ppHandle)
  588. {
  589. *ppHandle = (LPVOID *) pBatch;
  590. }
  591. else
  592. delete pBatch;
  593. }
  594. else
  595. delete pBatch;
  596. return dwRes;
  597. }
  598. long CBtrIndex::IndexEnumerationEnd(void *pHandle)
  599. {
  600. if (pHandle != INVALID_HANDLE_VALUE)
  601. delete (CIteratorBatch *) pHandle;
  602. return ERROR_SUCCESS;
  603. }
  604. long CBtrIndex::IndexEnumerationNext(void *pHandle, CFileName &wszFileName)
  605. {
  606. LPSTR pszString = 0;
  607. BOOL bRes;
  608. if (pHandle == 0 || pHandle == INVALID_HANDLE_VALUE)
  609. return ERROR_INVALID_PARAMETER;
  610. CIteratorBatch *pBatch = (CIteratorBatch *) pHandle;
  611. bRes = pBatch->Next(&pszString);
  612. if (bRes == FALSE)
  613. return ERROR_NO_MORE_FILES;
  614. CopyStringToWIN32_FIND_DATA(pszString, wszFileName);
  615. if (pszString)
  616. _BtrMemFree(pszString);
  617. return ERROR_SUCCESS;
  618. }