index_subsystem.c 32 KB

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