index_subsystem.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2005 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. #ifdef HAVE_CONFIG_H
  9. # include <config.h>
  10. #endif
  11. /* The indexing subsystem
  12. * ----------------------
  13. *
  14. * This provides support for indexing plugins and assigning
  15. * those plugins to sub-filters of a search filter. Currently
  16. * the old indexing code still exists and operates on those
  17. * indexes which do not have a plugin assigned. This indexing
  18. * abstraction is intended to eventually decouple the index mechanics
  19. * from the back-end where that is possible. Hopefully, while
  20. * supporting the needs of virtual attribute indexes, it will allow
  21. * easier integration of other back ends.
  22. *
  23. */
  24. /* includes */
  25. #include "slap.h"
  26. #include "./back-ldbm/back-ldbm.h"
  27. #include "./back-ldbm/idlapi.h"
  28. #include "index_subsys.h"
  29. #define INDEX_IDLIST_INITIAL_SIZE 128 /* make this a good size to avoid constant reallocs */
  30. /* data */
  31. static void **idl_api;
  32. struct _indexLinkedList
  33. {
  34. void *pNext;
  35. void *pPrev;
  36. };
  37. typedef struct _indexLinkedList indexLinkedList;
  38. struct _indexEntry
  39. {
  40. indexLinkedList list;
  41. char *indexedAttribute;
  42. Slapi_Filter *indexfilter;
  43. char *indexfilterstr;
  44. char **associated_attrs;
  45. void *user_data;
  46. Slapi_DN *namespace_dn;
  47. index_search_callback lookup_func; /* search call back */
  48. };
  49. typedef struct _indexEntry indexEntry;
  50. struct _indexPlugin
  51. {
  52. indexLinkedList list;
  53. char *id;
  54. indexEntry *indexes;
  55. index_validate_callback validate_op;
  56. };
  57. typedef struct _indexPlugin indexPlugin;
  58. struct _globalIndexCache
  59. {
  60. indexPlugin *pPlugins;
  61. indexEntry **ppIndexIndex; /* sorted list with key: indexEntry.indexedAttribute */
  62. int index_count;
  63. Slapi_RWLock *cache_lock;
  64. };
  65. typedef struct _globalIndexCache globalIndexCache;
  66. static globalIndexCache *theCache = 0;
  67. /* prototypes */
  68. static int index_subsys_decoder_done(Slapi_Filter *f);
  69. static int index_subsys_assign_decoders(Slapi_Filter *f);
  70. static int index_subsys_assign_decoder(Slapi_Filter *f);
  71. static int index_subsys_group_decoders(Slapi_Filter *f);
  72. static int index_subsys_unlink_subfilter(Slapi_Filter *fcomplex, Slapi_Filter *fsub);
  73. static int index_subsys_index_matches_associated(indexEntry *index, Slapi_Filter *f);
  74. /* matching alg - note : values 0/1/2/3 supported right now*/
  75. #define INDEX_MATCH_NONE 0
  76. #define INDEX_MATCH_EQUALITY 1
  77. #define INDEX_MATCH_PRESENCE 2
  78. #define INDEX_MATCH_SUBSTRING 3
  79. #define INDEX_MATCH_COMPLEX 4
  80. static int index_subsys_index_matches_filter(indexEntry *index, Slapi_Filter *f);
  81. static void index_subsys_read_lock()
  82. {
  83. slapi_rwlock_rdlock(theCache->cache_lock);
  84. }
  85. static void index_subsys_write_lock()
  86. {
  87. slapi_rwlock_wrlock(theCache->cache_lock);
  88. }
  89. static void index_subsys_unlock()
  90. {
  91. slapi_rwlock_unlock(theCache->cache_lock);
  92. }
  93. int slapi_index_entry_list_create(IndexEntryList **list)
  94. {
  95. if(idl_api)
  96. *list = (IndexEntryList*)IDList_alloc(idl_api, INDEX_IDLIST_INITIAL_SIZE);
  97. else
  98. *list = 0;
  99. return !(*list);
  100. }
  101. int slapi_index_entry_list_add(IndexEntryList **list, IndexEntryID id)
  102. {
  103. if(idl_api)
  104. IDList_insert(idl_api, (IDList **)list, (ID)id);
  105. return 0; /* no way to tell failure */
  106. }
  107. static int index_subsys_index_matches_filter(indexEntry *index, Slapi_Filter *f)
  108. {
  109. int ret = INDEX_MATCH_NONE;
  110. /* simple filters only right now */
  111. if(slapi_attr_types_equivalent(index->indexedAttribute, f->f_type))
  112. {
  113. /* ok we have some type of match, lets find out which */
  114. switch(index->indexfilter->f_choice)
  115. {
  116. case LDAP_FILTER_PRESENT:
  117. /* present means "x=*" */
  118. if(f->f_choice == LDAP_FILTER_PRESENT)
  119. ret = INDEX_MATCH_PRESENCE;
  120. break;
  121. case LDAP_FILTER_SUBSTRINGS:
  122. /* our equality filters look like this "x=**"
  123. * that means the filter will be assigned
  124. * a substring f_choice by the filter code
  125. * in str2filter.c
  126. * but we need to differentiate so we take
  127. * advantage of the fact that this creates a
  128. * special substring filter with no substring
  129. * to look for...
  130. */
  131. if( index->indexfilter->f_sub_initial == 0 &&
  132. index->indexfilter->f_sub_any == 0 &&
  133. index->indexfilter->f_sub_final == 0
  134. )
  135. {
  136. /* this is an index equality filter */
  137. if(f->f_choice == LDAP_FILTER_EQUALITY)
  138. ret = INDEX_MATCH_EQUALITY;
  139. }
  140. else
  141. {
  142. /* this is a regualar substring filter */
  143. if(f->f_choice == LDAP_FILTER_SUBSTRINGS)
  144. ret = INDEX_MATCH_SUBSTRING;
  145. }
  146. break;
  147. default:
  148. /* we don't know about any other type yet */
  149. break;
  150. }
  151. }
  152. return ret;
  153. }
  154. /* index_subsys_assign_filter_decoders
  155. * -----------------------------------
  156. * assigns index plugins to sub-filters
  157. */
  158. int index_subsys_assign_filter_decoders(Slapi_PBlock *pb)
  159. {
  160. int rc;
  161. Slapi_Filter *f;
  162. char *subsystem = "index_subsys_assign_filter_decoders";
  163. char logbuf[ 1024 ];
  164. /* extract the filter */
  165. slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &f);
  166. if ( LDAPDebugLevelIsSet( LDAP_DEBUG_FILTER ) && NULL != f ) {
  167. logbuf[0] = '\0';
  168. slapi_log_error( SLAPI_LOG_FATAL, subsystem, "before: %s\n",
  169. slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
  170. }
  171. /* find decoders */
  172. rc = index_subsys_assign_decoders(f);
  173. if ( LDAPDebugLevelIsSet( LDAP_DEBUG_FILTER ) && NULL != f ) {
  174. logbuf[0] = '\0';
  175. slapi_log_error( SLAPI_LOG_FATAL, subsystem, " after: %s\n",
  176. slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
  177. }
  178. return rc;
  179. }
  180. /* index_subsys_filter_decoders_done
  181. * ---------------------------------
  182. * removes assigned index plugins in
  183. * sub-filters
  184. */
  185. int index_subsys_filter_decoders_done(Slapi_PBlock *pb)
  186. {
  187. Slapi_Filter *f;
  188. /* extract the filter */
  189. slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &f);
  190. /* remove decoders */
  191. return index_subsys_decoder_done(f);
  192. }
  193. /* index_subsys_unlink_subfilter
  194. * -----------------------------
  195. * removes the sub-filter from
  196. * the complex filter list
  197. * does NOT deallocate the sub-filter
  198. */
  199. static int index_subsys_unlink_subfilter(Slapi_Filter *fcomplex, Slapi_Filter *fsub)
  200. {
  201. int ret = -1;
  202. Slapi_Filter *f;
  203. Slapi_Filter *f_prev = 0;
  204. for(f=fcomplex->f_list; f != NULL; f = f->f_next)
  205. {
  206. if(f == fsub)
  207. {
  208. if(f_prev)
  209. {
  210. f_prev->f_next = f->f_next;
  211. f->f_next = 0;
  212. ret = 0;
  213. break;
  214. }
  215. else
  216. {
  217. /* was at the beginning of the list */
  218. fcomplex->f_list = f->f_next;
  219. f->f_next = 0;
  220. ret = 0;
  221. break;
  222. }
  223. }
  224. f_prev = f;
  225. }
  226. return ret;
  227. }
  228. /* index_subsys_index_matches_associated
  229. * -------------------------------------
  230. * determines if there is any kind of match
  231. * between the specified type and the index.
  232. *
  233. * matches could be on the indexed type or
  234. * on any associated attribute
  235. * returns:
  236. * 0 when false
  237. * non-zero when true
  238. */
  239. static int index_subsys_index_matches_associated(indexEntry *index, Slapi_Filter *f)
  240. {
  241. int ret = 0;
  242. char **associated_attrs = index->associated_attrs;
  243. if(INDEX_MATCH_NONE != index_subsys_index_matches_filter(index, f))
  244. {
  245. /* matched on indexed attribute */
  246. ret = -1;
  247. goto bail;
  248. }
  249. /* check associated attributes */
  250. if(associated_attrs)
  251. {
  252. int i;
  253. char *type = f->f_type;
  254. for(i=0; associated_attrs[i]; i++)
  255. {
  256. if(slapi_attr_types_equivalent(associated_attrs[i], type))
  257. {
  258. /* matched on associated attribute */
  259. ret = -1;
  260. break;
  261. }
  262. }
  263. }
  264. bail:
  265. return ret;
  266. }
  267. /* index_subsys_flatten_filter
  268. * ---------------------------
  269. * takes a complex filter as argument (assumed)
  270. * and merges all compatible complex sub-filters
  271. * such that their list of sub-filters are moved
  272. * to the main list of sub-filters in f.
  273. *
  274. * This "flattens" the filter so that there are
  275. * the minimum number of nested complex filters
  276. * possible.
  277. *
  278. * What is a "compatible complex sub-filter?"
  279. * Answer: a complex sub-filter which is of the
  280. * same type (AND or OR) as the containing complex
  281. * filter and which is either assigned the same
  282. * index decoder or no index decoder is assigned to
  283. * either complex filter.
  284. *
  285. * This function assumes that it has already
  286. * been called for every complex sub-filter of f
  287. * i.e. it only looks one layer deep.
  288. *
  289. * Note that once a filter has been processed in
  290. * this fashion, rearranging the filter based
  291. * on the optimal evaluation order becomes very
  292. * much simpler. It should also have benefits for
  293. * performance when a filter is evaluated many
  294. * times since a linear list traversal is faster than a
  295. * context switch to recurse down into a complex
  296. * filter structure.
  297. *
  298. */
  299. static void index_subsys_flatten_filter(Slapi_Filter *flist)
  300. {
  301. struct slapi_filter *f = flist->f_list;
  302. struct slapi_filter *fprev = 0;
  303. struct slapi_filter *flast = 0;
  304. while(f)
  305. {
  306. if(f->assigned_decoder == flist->assigned_decoder)
  307. {
  308. /* mmmk, but is the filter complex? */
  309. if(f->f_choice == LDAP_FILTER_AND || f->f_choice == LDAP_FILTER_OR)
  310. {
  311. if(f->f_choice == flist->f_choice)
  312. {
  313. /* flatten this, and remember
  314. * we expect that any complex sub-filters
  315. * have already been flattened, so we
  316. * simply transfer the contents of this
  317. * sub-filter to the main sub-filter and
  318. * remove this complex sub-filter
  319. *
  320. * take care not to change the filter
  321. * ordering in any way (it may have been
  322. * optimized)
  323. */
  324. struct slapi_filter *fnext = f->f_next;
  325. struct slapi_filter *fsub = 0;
  326. while(f->f_list)
  327. {
  328. fsub = f->f_list;
  329. index_subsys_unlink_subfilter(f, f->f_list);
  330. fsub->f_next = fnext;
  331. if(flast)
  332. {
  333. /* we inserted something before - insert after */
  334. flast->f_next = fsub;
  335. }
  336. else
  337. {
  338. /* first insertion */
  339. if(fprev)
  340. {
  341. fprev->f_next = fsub;
  342. }
  343. else
  344. {
  345. /* insert at list start */
  346. flist->f_list = fsub;
  347. }
  348. fprev = fsub;
  349. }
  350. flast = fsub;
  351. }
  352. /* zero for dont recurse - recursing would
  353. * be bad since we have created a mutant
  354. * complex filter with no children
  355. */
  356. slapi_filter_free(f, 0);
  357. f = fnext;
  358. }
  359. else
  360. {
  361. /* don't loose a nested filter having a different choice */
  362. if (flast) {
  363. flast->f_next = f;
  364. flast = f;
  365. }
  366. fprev = f;
  367. f = f->f_next;
  368. }
  369. }
  370. else
  371. {
  372. /* don't loose a simple filter */
  373. if (flast) {
  374. flast->f_next = f;
  375. flast = f;
  376. }
  377. fprev = f;
  378. f = f->f_next;
  379. }
  380. }
  381. else
  382. {
  383. fprev = f;
  384. f = f->f_next;
  385. }
  386. }
  387. }
  388. /* index_subsys_group_decoders
  389. * ---------------------------
  390. * looks for grouping opportunities
  391. * such that a complex filter may
  392. * be assigned to a single index.
  393. *
  394. * it is assumed that any complex sub-filters
  395. * have already been assigned decoders
  396. * using this function if it
  397. * was possible to do so
  398. */
  399. static int index_subsys_group_decoders(Slapi_Filter *flist)
  400. {
  401. int ret = 0;
  402. struct slapi_filter *f = 0;
  403. struct slapi_filter *f_indexed = 0;
  404. struct slapi_filter *fhead = 0;
  405. int index_count = 0;
  406. int matched = 1;
  407. switch(flist->f_choice)
  408. {
  409. case LDAP_FILTER_AND:
  410. case LDAP_FILTER_OR:
  411. break;
  412. default:
  413. /* any other result not handled by this code */
  414. goto bail;
  415. }
  416. /* make sure we start with an unassigned filter */
  417. flist->assigned_decoder = 0;
  418. /* Since this function is about optimal grouping of complex filters,
  419. * lets explain what is happening here:
  420. *
  421. * Beyond detecting that what was passed in is already optimal,
  422. * there are 4 basic problems we need to solve here:
  423. *
  424. * Input this function Output
  425. * 1) (&(indexed)(other)(associated)) -> X -> (&(&(indexed)(associated))(other))
  426. * 2) (&(&(indexed)(other))(associated)) -> X -> (&(&(indexed)(associated))(other))
  427. * 3) (&(&(associated)(other))(indexed)) -> X -> (&(&(indexed)(associated))(other))
  428. * 4) (&(&(indexed)(associated))(associated)) -> X -> (&(indexed)(associated)(associated))
  429. *
  430. * To avoid having special code for 2) and 3) we make them look like
  431. * 1) by flattening the filter - note this will only flatten subfilters
  432. * which have no decoder assigned since the filter we flatten has no
  433. * decoder assigned - and this behaviour is exactly what we want.
  434. * 4) is a special case of 1) and since that is the case, we can allow
  435. * the code for 1) to process it but make sure we flatten the filter
  436. * before exit. If 4) is exactly as stated without any other non-indexed
  437. * or associated references then in fact it will be detected as a completely
  438. * matching filter prior to reaching the code for 1).
  439. */
  440. index_subsys_flatten_filter(flist);
  441. fhead = flist->f_list;
  442. /* find the first index assigned */
  443. for ( f_indexed = fhead; f_indexed != NULL; f_indexed = f_indexed->f_next )
  444. {
  445. if( f_indexed->assigned_decoder )
  446. {
  447. /* non-null decoder means assigned */
  448. break;
  449. }
  450. }
  451. if(NULL == f_indexed)
  452. /* nothing to process */
  453. goto bail;
  454. /* determine if whole filter matches
  455. * to avoid allocations where it is
  456. * not necessary
  457. */
  458. for ( f = fhead; f != NULL; f = f->f_next )
  459. {
  460. if(f->assigned_decoder != f_indexed->assigned_decoder)
  461. {
  462. switch(f->f_choice)
  463. {
  464. case LDAP_FILTER_AND:
  465. case LDAP_FILTER_OR:
  466. /*
  467. * All complex subfilters are guaranteed to have the correct
  468. * decoder assigned already, so this is a mismatch.
  469. */
  470. matched = 0;
  471. break;
  472. default:
  473. if(!index_subsys_index_matches_associated(f_indexed->assigned_decoder, f))
  474. {
  475. matched = 0;
  476. }
  477. break;
  478. }
  479. if(!matched)
  480. break;
  481. }
  482. }
  483. if(matched)
  484. {
  485. /* whole filter matches - assign to this decoder */
  486. flist->assigned_decoder = f_indexed->assigned_decoder;
  487. /* finally lets flatten this filter if possible
  488. * Didn't we do that already? No, we flattened the
  489. * filter *prior* to assigning a decoder
  490. */
  491. index_subsys_flatten_filter(flist);
  492. goto bail;
  493. }
  494. /* whole filter does not match so,
  495. * if the sub-filter count is > 2
  496. * for each assigned sub-filter,
  497. * match other groupable filters
  498. * and extract them into another sub-filter
  499. */
  500. /* count */
  501. for ( f = fhead; f != NULL && index_count < 3; f = f->f_next )
  502. {
  503. index_count++;
  504. }
  505. if(index_count > 2)
  506. {
  507. /* this is where we start re-arranging the filter assertions
  508. * into groups which can be serviced by a single plugin
  509. * at this point we know that:
  510. * a) the filter has at least 2 assertions that cannot be grouped
  511. * b) there are more than 2 assertions and so grouping is still possible
  512. */
  513. struct slapi_filter *f_listposition=f_indexed; /* flist subfilter list iterator */
  514. int main_iterate; /* controls whether to iterate to the next sub-filter of flist */
  515. while(f_listposition)
  516. {
  517. /* the target grouping container - we move sub-filters here */
  518. struct slapi_filter *targetf=0;
  519. /* indicates we found an existing targetf */
  520. int assigned = 0;
  521. /* something to join with next compatible
  522. * subfilter we find - this will be the
  523. * first occurence of a filter assigned
  524. * to a particular decoder
  525. */
  526. struct slapi_filter *saved_filter = 0;
  527. struct slapi_filter *f_tmp = 0; /* save filter for list fixups */
  528. /* controls whether to iterate to the
  529. * next sub-filter of flist
  530. * inner loop
  531. */
  532. int iterate = 1;
  533. f_indexed = f_listposition;
  534. main_iterate = 1;
  535. /* finding a convenient existing sub-filter of the same
  536. * type as the containing filter avoids allocation
  537. * so lets look for one
  538. */
  539. for ( f = fhead; f != NULL; f = f->f_next)
  540. {
  541. switch(f->f_choice)
  542. {
  543. case LDAP_FILTER_AND:
  544. case LDAP_FILTER_OR:
  545. if( f->f_choice == flist->f_choice &&
  546. f->assigned_decoder == f_indexed->assigned_decoder)
  547. {
  548. targetf = f;
  549. assigned = 1;
  550. }
  551. break;
  552. default:
  553. break;
  554. }
  555. if(assigned)
  556. break;
  557. }
  558. /* now look for grouping opportunities */
  559. for ( f = fhead; f != NULL; (iterate && f) ? f = f->f_next : f )
  560. {
  561. iterate = 1;
  562. if(f != targetf)
  563. {
  564. switch(f->f_choice)
  565. {
  566. case LDAP_FILTER_AND:
  567. case LDAP_FILTER_OR:
  568. if( (targetf && f->f_choice == targetf->f_choice)
  569. && f->assigned_decoder == f_indexed->assigned_decoder)
  570. {
  571. /* ok we have a complex filter we can group - group it
  572. * it is worth noting that if we got here, then we must
  573. * have found a complex filter suitable for for putting
  574. * sub-filters in, so there is no need to add the newly
  575. * merged complex filter to the main complex filter,
  576. * since it is already there
  577. */
  578. /* main filter list fix ups */
  579. f_tmp = f;
  580. f = f->f_next;
  581. iterate = 0;
  582. if(f_tmp == f_listposition)
  583. {
  584. f_listposition = f;
  585. main_iterate = 0;
  586. }
  587. /* remove f from the main complex filter */
  588. index_subsys_unlink_subfilter(flist, f_tmp);
  589. /* merge - note, not true merge since f gets
  590. * added to targetf as a sub-filter
  591. */
  592. slapi_filter_join_ex(targetf->f_choice, targetf, f_tmp, 0);
  593. /* since it was not a true merge, lets do the true merge now */
  594. index_subsys_flatten_filter(targetf);
  595. }
  596. break;
  597. default:
  598. if(index_subsys_index_matches_associated(f_indexed->assigned_decoder, f))
  599. {
  600. if(targetf)
  601. {
  602. /* main filter list fix ups */
  603. f_tmp = f;
  604. f = f->f_next;
  605. iterate = 0;
  606. if(f_tmp == f_listposition)
  607. {
  608. f_listposition = f;
  609. main_iterate = 0;
  610. }
  611. index_subsys_unlink_subfilter(flist, f_tmp);
  612. targetf = slapi_filter_join_ex( targetf->f_choice, targetf, f_tmp, 0 );
  613. }
  614. else
  615. {
  616. if(saved_filter)
  617. {
  618. /* main filter list fix ups */
  619. f_tmp = f;
  620. f = f->f_next;
  621. iterate = 0;
  622. if(f_tmp == f_listposition)
  623. {
  624. f_listposition = f;
  625. main_iterate = 0;
  626. }
  627. index_subsys_unlink_subfilter(flist, f_tmp);
  628. index_subsys_unlink_subfilter(flist, saved_filter);
  629. targetf = slapi_filter_join_ex( flist->f_choice, saved_filter, f_tmp, 0 );
  630. targetf->assigned_decoder = f_indexed->assigned_decoder;
  631. }
  632. else
  633. {
  634. /* nothing to join so save this for
  635. * when we find another compatible
  636. * filter
  637. */
  638. saved_filter = f;
  639. }
  640. }
  641. if(!assigned && targetf)
  642. {
  643. /* targetf has just been created, so
  644. * we must add it to the main complex filter
  645. */
  646. targetf->f_next = flist->f_list;
  647. flist->f_list = targetf;
  648. assigned = 1;
  649. }
  650. }
  651. break;
  652. }
  653. }
  654. }
  655. /* iterate through the main list
  656. * to the next indexed sub-filter
  657. */
  658. if( f_listposition &&
  659. (main_iterate ||
  660. (!main_iterate &&
  661. !f_listposition->assigned_decoder)))
  662. {
  663. if(!f_listposition->f_next)
  664. {
  665. f_listposition = 0;
  666. break;
  667. }
  668. for ( f_listposition = f_listposition->f_next; f_listposition != NULL; f_listposition = f_listposition->f_next )
  669. {
  670. if( f_listposition->assigned_decoder )
  671. {
  672. /* non-null decoder means assigned */
  673. break;
  674. }
  675. }
  676. }
  677. }
  678. }
  679. bail:
  680. return ret;
  681. }
  682. /* index_subsys_assign_decoders
  683. * ----------------------------
  684. * recurses through complex filters
  685. * assigning decoders
  686. */
  687. static int index_subsys_assign_decoders(Slapi_Filter *f)
  688. {
  689. int ret = 0;
  690. Slapi_Filter *subf;
  691. switch ( slapi_filter_get_choice( f ) )
  692. {
  693. case LDAP_FILTER_AND:
  694. case LDAP_FILTER_OR:
  695. case LDAP_FILTER_NOT:
  696. /* assign simple filters first */
  697. f->assigned_decoder = 0;
  698. for(subf=f->f_list; subf != NULL; subf = subf->f_next )
  699. ret = index_subsys_assign_decoders(subf);
  700. /* now check for filter grouping opportunities... */
  701. if(slapi_filter_get_choice( f ) != LDAP_FILTER_NOT)
  702. index_subsys_group_decoders(f);
  703. else
  704. {
  705. /* LDAP_FILTER_NOT is a special case
  706. * the contained sub-filter determines
  707. * the assigned index - the index plugin has
  708. * the option to refuse to service the
  709. * NOT filter when it is presented
  710. */
  711. f->assigned_decoder = f->f_list->assigned_decoder;
  712. }
  713. break;
  714. default:
  715. /* find a decoder that fits this simple filter */
  716. ret = index_subsys_assign_decoder(f);
  717. }
  718. return ret;
  719. }
  720. /* index_subsys_decoder_done
  721. * -------------------------
  722. * recurses through complex filters
  723. * removing decoders
  724. */
  725. static int index_subsys_decoder_done(Slapi_Filter *f)
  726. {
  727. int ret = 0;
  728. Slapi_Filter *subf;
  729. indexEntry *index;
  730. indexEntry *next_index;
  731. switch ( slapi_filter_get_choice( f ) )
  732. {
  733. case LDAP_FILTER_AND:
  734. case LDAP_FILTER_OR:
  735. case LDAP_FILTER_NOT:
  736. /* remove simple filters first */
  737. for(subf=f->f_list; subf != NULL; subf = subf->f_next )
  738. ret = index_subsys_decoder_done(subf);
  739. break;
  740. default:
  741. /* free the decoders - shallow free */
  742. index = f->assigned_decoder;
  743. while(index)
  744. {
  745. next_index = index->list.pNext;
  746. slapi_ch_free((void**)index);
  747. index = next_index;
  748. }
  749. f->assigned_decoder = 0;
  750. }
  751. return ret;
  752. }
  753. /* index_subsys_evaluate_filter
  754. * ----------------------------
  755. * passes the filter to the correct plugin
  756. * index_subsys_assign_filter_decoders() must
  757. * have been called previously on this filter
  758. * this function can be safely called on all
  759. * filters post index_subsys_assign_filter_decoders()
  760. * whether they are assigned to a plugin or not
  761. *
  762. * returns:
  763. * INDEX_FILTER_EVALUTED: a candidate list is produced
  764. * INDEX_FILTER_UNEVALUATED: filter not considered
  765. */
  766. int index_subsys_evaluate_filter(Slapi_Filter *f, Slapi_DN *namespace_dn, IndexEntryList **out)
  767. {
  768. int ret = INDEX_FILTER_UNEVALUATED;
  769. indexEntry *index = (indexEntry*)f->assigned_decoder;
  770. if(index && theCache)
  771. {
  772. index_subsys_read_lock();
  773. /* there is a list of indexes which may
  774. * provide an answer for this filter, we
  775. * need to invoke the first one that matches
  776. * the namespace requested
  777. */
  778. for(; index; index = index->list.pNext)
  779. {
  780. /* check namespace */
  781. if(slapi_sdn_compare(index->namespace_dn, namespace_dn))
  782. {
  783. /* wrong namespace */
  784. continue;
  785. }
  786. /* execute the search */
  787. if(index->lookup_func)
  788. {
  789. ret = (index->lookup_func)(f, out, index->user_data);
  790. break;
  791. }
  792. }
  793. index_subsys_unlock();
  794. }
  795. return ret;
  796. }
  797. /* slapi_index_register_decoder
  798. * ----------------------------
  799. * This allows a decoder to register itself,
  800. * it also builds the initial cache when first
  801. * called. Note, there is no way to deregister
  802. * once registered - this allows a lock free cache
  803. * at the expense of a restart to clear old
  804. * indexes, this shouldnt be a problem since it is
  805. * not expected that indexes will be removed
  806. * often.
  807. */
  808. int slapi_index_register_decoder(char *plugin_id, index_validate_callback validate_op)
  809. {
  810. static int firstTime = 1;
  811. static int gotIDLapi = 0;
  812. int ret = 0;
  813. indexPlugin *plg;
  814. if(firstTime)
  815. {
  816. /* create the cache */
  817. theCache = (globalIndexCache*)slapi_ch_malloc(sizeof(globalIndexCache));
  818. if(theCache)
  819. {
  820. theCache->pPlugins = 0;
  821. theCache->ppIndexIndex = 0;
  822. theCache->index_count = 0;
  823. theCache->cache_lock = slapi_new_rwlock();
  824. firstTime = 0;
  825. if(!gotIDLapi)
  826. {
  827. if(slapi_apib_get_interface(IDL_v1_0_GUID, &idl_api))
  828. {
  829. gotIDLapi = 1;
  830. }
  831. }
  832. }
  833. else
  834. {
  835. ret = -1;
  836. goto bail;
  837. }
  838. }
  839. index_subsys_write_lock();
  840. /* add the index decoder to the cache - no checks, better register once only*/
  841. plg = (indexPlugin*)slapi_ch_malloc(sizeof(indexPlugin));
  842. if(plg)
  843. {
  844. plg->id = slapi_ch_strdup(plugin_id);
  845. plg->indexes = 0;
  846. plg->validate_op = validate_op;
  847. /* we always add to the start of the linked list */
  848. plg->list.pPrev = 0;
  849. if(theCache->pPlugins)
  850. {
  851. plg->list.pNext = theCache->pPlugins;
  852. theCache->pPlugins->list.pPrev = plg;
  853. }
  854. else
  855. plg->list.pNext = 0;
  856. theCache->pPlugins = plg;
  857. }
  858. else
  859. ret = -1;
  860. index_subsys_unlock();
  861. bail:
  862. return ret;
  863. }
  864. /* slapi_index_register_index
  865. * --------------------------
  866. * a plugin that has registered itself may
  867. * then proceed to register individual indexes
  868. * that it looks after. This function adds
  869. * the indexes to the plugin cache.
  870. */
  871. int slapi_index_register_index(char *plugin_id, indexed_item *registration_item, void *user_data)
  872. {
  873. int ret = 0;
  874. indexPlugin *plg;
  875. indexEntry *index;
  876. int a_matched_index = 0;
  877. Slapi_Filter *tmp_f = slapi_str2filter(registration_item->index_filter);
  878. Slapi_Backend *be;
  879. if(!theCache || !tmp_f)
  880. return -1;
  881. index_subsys_write_lock();
  882. /* first lets find the plugin */
  883. plg = theCache->pPlugins;
  884. while(plg)
  885. {
  886. if(!slapi_UTF8CASECMP(plugin_id, plg->id))
  887. {
  888. /* found plugin */
  889. break;
  890. }
  891. plg = plg->list.pNext;
  892. }
  893. if(0 == plg)
  894. {
  895. /* not found */
  896. ret = -1;
  897. goto bail;
  898. }
  899. /* map the namespace dn to a backend dn */
  900. be = slapi_be_select( registration_item->namespace_dn );
  901. if(be == defbackend_get_backend())
  902. {
  903. ret = -1;
  904. goto bail;
  905. }
  906. /* now add the new index - we shall assume indexes
  907. * will not be registered twice by different plugins,
  908. * in that event, the last one added wins
  909. * the first matching index in the list is always
  910. * the current one, other matching indexes are ignored
  911. * therefore reregistering an index with NULL
  912. * callbacks disables the index for that plugin
  913. */
  914. /* find the index if already registered */
  915. index = plg->indexes;
  916. while(index)
  917. {
  918. if(index_subsys_index_matches_filter(index, tmp_f))
  919. {
  920. /* found it - free what is currently there, it will be replaced */
  921. slapi_ch_free((void**)&index->indexfilterstr);
  922. slapi_filter_free(index->indexfilter, 1);
  923. slapi_ch_free((void**)&index->indexedAttribute);
  924. charray_free( index->associated_attrs );
  925. index->associated_attrs = 0;
  926. a_matched_index = 1;
  927. break;
  928. }
  929. index = index->list.pNext;
  930. }
  931. if(!index)
  932. index = (indexEntry*)slapi_ch_calloc(1,sizeof(indexEntry));
  933. index->indexfilterstr = slapi_ch_strdup(registration_item->index_filter);
  934. index->indexfilter = tmp_f;
  935. index->lookup_func = registration_item->search_op;
  936. index->user_data = user_data;
  937. index->namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
  938. /* for now, we support simple filters only */
  939. index->indexedAttribute = slapi_ch_strdup(index->indexfilter->f_type);
  940. /* add associated attributes */
  941. if(registration_item->associated_attrs)
  942. {
  943. index->associated_attrs =
  944. cool_charray_dup( registration_item->associated_attrs );
  945. }
  946. if(!a_matched_index)
  947. {
  948. if(plg->indexes)
  949. {
  950. index->list.pNext = plg->indexes;
  951. plg->indexes->list.pPrev = plg;
  952. }
  953. else
  954. index->list.pNext = 0;
  955. index->list.pPrev = 0;
  956. plg->indexes = index;
  957. theCache->index_count++;
  958. }
  959. /* now we need to rebuild the index (onto the indexed items)
  960. * this is a bit inefficient since
  961. * every new index that is added triggers
  962. * an index rebuild - but this is countered
  963. * by the fact this will probably happen once
  964. * at start up most of the time, and very rarely
  965. * otherwise, so normal server performance should
  966. * not be unduly effected effected
  967. * we take care to build the index and only then swap it in
  968. * for the old one
  969. * PARPAR: we need to RW (or maybe a ref count) lock here
  970. * only alternative would be to not have an index :(
  971. * for few plugins with few indexes thats a possibility
  972. * traditionally many indexes have not been a good idea
  973. * anyway so...
  974. */
  975. /* indexIndex = (indexEntry**)slapi_ch_malloc(sizeof(indexEntry*) * (theCache->index_count+1));
  976. */
  977. /* for now, lets see how fast things are without an index
  978. * that should not be a problem at all to begin with since
  979. * presence will be the only index decoder. Additionally,
  980. * adding an index means we need locks - um, no.
  981. * so no more to do
  982. */
  983. bail:
  984. index_subsys_unlock();
  985. return ret;
  986. }
  987. /* index_subsys_index_matches_index
  988. * --------------------------------
  989. * criteria for a match is that the types
  990. * are the same and that all the associated
  991. * attributes that are configured for cmp_to
  992. * are also in cmp_with.
  993. */
  994. int index_subsys_index_matches_index(indexEntry *cmp_to, indexEntry *cmp_with)
  995. {
  996. int ret = 0;
  997. if(slapi_attr_types_equivalent(cmp_to->indexedAttribute, cmp_with->indexedAttribute))
  998. {
  999. /* now check associated */
  1000. if(cmp_to->associated_attrs)
  1001. {
  1002. if(cmp_with->associated_attrs)
  1003. {
  1004. int x,y;
  1005. ret = 1;
  1006. for(x=0; cmp_to->associated_attrs[x] && ret == 1; x++)
  1007. {
  1008. ret = 0;
  1009. for(y=0; cmp_with->associated_attrs[y]; y++)
  1010. {
  1011. if(slapi_attr_types_equivalent(
  1012. cmp_to->associated_attrs[x],
  1013. cmp_with->associated_attrs[y]
  1014. ))
  1015. {
  1016. /* matched on associated attribute */
  1017. ret = 1;
  1018. break;
  1019. }
  1020. }
  1021. }
  1022. }
  1023. }
  1024. else
  1025. {
  1026. /* no associated is an auto match */
  1027. ret = 1;
  1028. }
  1029. }
  1030. return ret;
  1031. }
  1032. indexEntry *index_subsys_index_shallow_dup(indexEntry *dup_this)
  1033. {
  1034. indexEntry *ret = (indexEntry *)slapi_ch_calloc(1,sizeof(indexEntry));
  1035. /* shallow copy - dont copy linked list pointers */
  1036. ret->indexedAttribute = dup_this->indexedAttribute;
  1037. ret->indexfilter = dup_this->indexfilter;
  1038. ret->indexfilterstr = dup_this->indexfilterstr;
  1039. ret->user_data = dup_this->user_data;
  1040. ret->namespace_dn = dup_this->namespace_dn;
  1041. ret->lookup_func = dup_this->lookup_func;
  1042. ret->associated_attrs = dup_this->associated_attrs;
  1043. return ret;
  1044. }
  1045. /* index_subsys_assign_decoder
  1046. * ---------------------------
  1047. * finds a decoder which will service
  1048. * the filter if one is available and assigns
  1049. * the decoder to the filter. Currently this
  1050. * function supports only simple filters, but
  1051. * may in the future support complex filter
  1052. * assignment (possibly including filter rewriting
  1053. * to make more matches possible)
  1054. *
  1055. * populates f->alternate_decoders if more than one
  1056. * index could deal with a filter - only filters that
  1057. * have a match with all associated attributes of the
  1058. * first found filter are said to match - their
  1059. * namespaces may be different
  1060. */
  1061. static int index_subsys_assign_decoder(Slapi_Filter *f)
  1062. {
  1063. int ret = 0; /* always succeed */
  1064. indexPlugin *plg;
  1065. indexEntry *index = 0;
  1066. indexEntry *last = 0;
  1067. f->assigned_decoder = 0;
  1068. if(!theCache)
  1069. return 0;
  1070. index_subsys_read_lock();
  1071. plg = theCache->pPlugins;
  1072. while(plg)
  1073. {
  1074. index = plg->indexes;
  1075. while(index)
  1076. {
  1077. if(INDEX_MATCH_NONE != index_subsys_index_matches_filter(index, f))
  1078. {
  1079. /* we have a match, assign this decoder if not disabled */
  1080. if(index->lookup_func)
  1081. {
  1082. if(!f->assigned_decoder)
  1083. {
  1084. f->assigned_decoder = index_subsys_index_shallow_dup(index);
  1085. last = f->assigned_decoder;
  1086. }
  1087. else
  1088. {
  1089. /* add to alternate list - we require that they all
  1090. * have the same associated attributes configuration for now
  1091. * though they may have different namespaces
  1092. */
  1093. if(index_subsys_index_matches_index(f->assigned_decoder, index))
  1094. {
  1095. /* add to end */
  1096. last->list.pNext = index_subsys_index_shallow_dup(index);
  1097. last = last->list.pNext;
  1098. }
  1099. }
  1100. }
  1101. else
  1102. {
  1103. /* index disabled, so we must allow another plugin to
  1104. * get a crack at servicing the index
  1105. */
  1106. break;
  1107. }
  1108. }
  1109. index = index->list.pNext;
  1110. }
  1111. plg = plg->list.pNext;
  1112. }
  1113. index_subsys_unlock();
  1114. return ret;
  1115. }