index_subsystem.c 32 KB

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