index_subsystem.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  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. fprev = f;
  397. f = f->f_next;
  398. }
  399. }
  400. else
  401. {
  402. fprev = f;
  403. f = f->f_next;
  404. }
  405. }
  406. }
  407. /* index_subsys_group_decoders
  408. * ---------------------------
  409. * looks for grouping opportunities
  410. * such that a complex filter may
  411. * be assigned to a single index.
  412. *
  413. * it is assumed that any complex sub-filters
  414. * have already been assigned decoders
  415. * using this function if it
  416. * was possible to do so
  417. */
  418. static int index_subsys_group_decoders(Slapi_Filter *flist)
  419. {
  420. int ret = 0;
  421. struct slapi_filter *f = 0;
  422. struct slapi_filter *f_indexed = 0;
  423. struct slapi_filter *fhead = 0;
  424. int index_count = 0;
  425. int matched = 1;
  426. switch(flist->f_choice)
  427. {
  428. case LDAP_FILTER_AND:
  429. case LDAP_FILTER_OR:
  430. break;
  431. default:
  432. /* any other result not handled by this code */
  433. goto bail;
  434. }
  435. /* make sure we start with an unassigned filter */
  436. flist->assigned_decoder = 0;
  437. /* Since this function is about optimal grouping of complex filters,
  438. * lets explain what is happening here:
  439. *
  440. * Beyond detecting that what was passed in is already optimal,
  441. * there are 4 basic problems we need to solve here:
  442. *
  443. * Input this function Output
  444. * 1) (&(indexed)(other)(associated)) -> X -> (&(&(indexed)(associated))(other))
  445. * 2) (&(&(indexed)(other))(associated)) -> X -> (&(&(indexed)(associated))(other))
  446. * 3) (&(&(associated)(other))(indexed)) -> X -> (&(&(indexed)(associated))(other))
  447. * 4) (&(&(indexed)(associated))(associated)) -> X -> (&(indexed)(associated)(associated))
  448. *
  449. * To avoid having special code for 2) and 3) we make them look like
  450. * 1) by flattening the filter - note this will only flatten subfilters
  451. * which have no decoder assigned since the filter we flatten has no
  452. * decoder assigned - and this behaviour is exactly what we want.
  453. * 4) is a special case of 1) and since that is the case, we can allow
  454. * the code for 1) to process it but make sure we flatten the filter
  455. * before exit. If 4) is exactly as stated without any other non-indexed
  456. * or associated references then in fact it will be detected as a completely
  457. * matching filter prior to reaching the code for 1).
  458. */
  459. index_subsys_flatten_filter(flist);
  460. fhead = flist->f_list;
  461. /* find the first index assigned */
  462. for ( f_indexed = fhead; f_indexed != NULL; f_indexed = f_indexed->f_next )
  463. {
  464. if( f_indexed->assigned_decoder )
  465. {
  466. /* non-null decoder means assigned */
  467. break;
  468. }
  469. }
  470. if(NULL == f_indexed)
  471. /* nothing to process */
  472. goto bail;
  473. /* determine if whole filter matches
  474. * to avoid allocations where it is
  475. * not necessary
  476. */
  477. for ( f = fhead; f != NULL; f = f->f_next )
  478. {
  479. if(f->assigned_decoder != f_indexed->assigned_decoder)
  480. {
  481. switch(f->f_choice)
  482. {
  483. case LDAP_FILTER_AND:
  484. case LDAP_FILTER_OR:
  485. /*
  486. * All complex subfilters are guaranteed to have the correct
  487. * decoder assigned already, so this is a mismatch.
  488. */
  489. matched = 0;
  490. break;
  491. default:
  492. if(!index_subsys_index_matches_associated(f_indexed->assigned_decoder, f))
  493. {
  494. matched = 0;
  495. }
  496. break;
  497. }
  498. if(!matched)
  499. break;
  500. }
  501. }
  502. if(matched)
  503. {
  504. /* whole filter matches - assign to this decoder */
  505. flist->assigned_decoder = f_indexed->assigned_decoder;
  506. /* finally lets flatten this filter if possible
  507. * Didn't we do that already? No, we flattened the
  508. * filter *prior* to assigning a decoder
  509. */
  510. index_subsys_flatten_filter(flist);
  511. goto bail;
  512. }
  513. /* whole filter does not match so,
  514. * if the sub-filter count is > 2
  515. * for each assigned sub-filter,
  516. * match other groupable filters
  517. * and extract them into another sub-filter
  518. */
  519. /* count */
  520. for ( f = fhead; f != NULL && index_count < 3; f = f->f_next )
  521. {
  522. index_count++;
  523. }
  524. if(index_count > 2)
  525. {
  526. /* this is where we start re-arranging the filter assertions
  527. * into groups which can be serviced by a single plugin
  528. * at this point we know that:
  529. * a) the filter has at least 2 assertions that cannot be grouped
  530. * b) there are more than 2 assertions and so grouping is still possible
  531. */
  532. struct slapi_filter *f_listposition=f_indexed; /* flist subfilter list iterator */
  533. int main_iterate; /* controls whether to iterate to the next sub-filter of flist */
  534. while(f_listposition)
  535. {
  536. /* the target grouping container - we move sub-filters here */
  537. struct slapi_filter *targetf=0;
  538. /* indicates we found an existing targetf */
  539. int assigned = 0;
  540. /* something to join with next compatible
  541. * subfilter we find - this will be the
  542. * first occurence of a filter assigned
  543. * to a particular decoder
  544. */
  545. struct slapi_filter *saved_filter = 0;
  546. struct slapi_filter *f_tmp = 0; /* save filter for list fixups */
  547. /* controls whether to iterate to the
  548. * next sub-filter of flist
  549. * inner loop
  550. */
  551. int iterate = 1;
  552. f_indexed = f_listposition;
  553. main_iterate = 1;
  554. /* finding a convenient existing sub-filter of the same
  555. * type as the containing filter avoids allocation
  556. * so lets look for one
  557. */
  558. for ( f = fhead; f != NULL; f = f->f_next)
  559. {
  560. switch(f->f_choice)
  561. {
  562. case LDAP_FILTER_AND:
  563. case LDAP_FILTER_OR:
  564. if( f->f_choice == flist->f_choice &&
  565. f->assigned_decoder == f_indexed->assigned_decoder)
  566. {
  567. targetf = f;
  568. assigned = 1;
  569. }
  570. break;
  571. default:
  572. break;
  573. }
  574. if(assigned)
  575. break;
  576. }
  577. /* now look for grouping opportunities */
  578. for ( f = fhead; f != NULL; (iterate && f) ? f = f->f_next : f )
  579. {
  580. iterate = 1;
  581. if(f != targetf)
  582. {
  583. switch(f->f_choice)
  584. {
  585. case LDAP_FILTER_AND:
  586. case LDAP_FILTER_OR:
  587. if( (targetf && f->f_choice == targetf->f_choice)
  588. && f->assigned_decoder == f_indexed->assigned_decoder)
  589. {
  590. /* ok we have a complex filter we can group - group it
  591. * it is worth noting that if we got here, then we must
  592. * have found a complex filter suitable for for putting
  593. * sub-filters in, so there is no need to add the newly
  594. * merged complex filter to the main complex filter,
  595. * since it is already there
  596. */
  597. /* main filter list fix ups */
  598. f_tmp = f;
  599. f = f->f_next;
  600. iterate = 0;
  601. if(f_tmp == f_listposition)
  602. {
  603. f_listposition = f;
  604. main_iterate = 0;
  605. }
  606. /* remove f from the main complex filter */
  607. index_subsys_unlink_subfilter(flist, f_tmp);
  608. /* merge - note, not true merge since f gets
  609. * added to targetf as a sub-filter
  610. */
  611. slapi_filter_join_ex(targetf->f_choice, targetf, f_tmp, 0);
  612. /* since it was not a true merge, lets do the true merge now */
  613. index_subsys_flatten_filter(targetf);
  614. }
  615. break;
  616. default:
  617. if(index_subsys_index_matches_associated(f_indexed->assigned_decoder, f))
  618. {
  619. if(targetf)
  620. {
  621. /* main filter list fix ups */
  622. f_tmp = f;
  623. f = f->f_next;
  624. iterate = 0;
  625. if(f_tmp == f_listposition)
  626. {
  627. f_listposition = f;
  628. main_iterate = 0;
  629. }
  630. index_subsys_unlink_subfilter(flist, f_tmp);
  631. targetf = slapi_filter_join_ex( targetf->f_choice, targetf, f_tmp, 0 );
  632. }
  633. else
  634. {
  635. if(saved_filter)
  636. {
  637. /* main filter list fix ups */
  638. f_tmp = f;
  639. f = f->f_next;
  640. iterate = 0;
  641. if(f_tmp == f_listposition)
  642. {
  643. f_listposition = f;
  644. main_iterate = 0;
  645. }
  646. index_subsys_unlink_subfilter(flist, f_tmp);
  647. index_subsys_unlink_subfilter(flist, saved_filter);
  648. targetf = slapi_filter_join_ex( flist->f_choice, saved_filter, f_tmp, 0 );
  649. targetf->assigned_decoder = f_indexed->assigned_decoder;
  650. }
  651. else
  652. {
  653. /* nothing to join so save this for
  654. * when we find another compatible
  655. * filter
  656. */
  657. saved_filter = f;
  658. }
  659. }
  660. if(!assigned && targetf)
  661. {
  662. /* targetf has just been created, so
  663. * we must add it to the main complex filter
  664. */
  665. targetf->f_next = flist->f_list;
  666. flist->f_list = targetf;
  667. assigned = 1;
  668. }
  669. }
  670. break;
  671. }
  672. }
  673. }
  674. /* iterate through the main list
  675. * to the next indexed sub-filter
  676. */
  677. if( f_listposition &&
  678. (main_iterate ||
  679. (!main_iterate &&
  680. !f_listposition->assigned_decoder)))
  681. {
  682. if(!f_listposition->f_next)
  683. {
  684. f_listposition = 0;
  685. break;
  686. }
  687. for ( f_listposition = f_listposition->f_next; f_listposition != NULL; f_listposition = f_listposition->f_next )
  688. {
  689. if( f_listposition->assigned_decoder )
  690. {
  691. /* non-null decoder means assigned */
  692. break;
  693. }
  694. }
  695. }
  696. }
  697. }
  698. bail:
  699. return ret;
  700. }
  701. /* index_subsys_assign_decoders
  702. * ----------------------------
  703. * recurses through complex filters
  704. * assigning decoders
  705. */
  706. static int index_subsys_assign_decoders(Slapi_Filter *f)
  707. {
  708. int ret = 0;
  709. Slapi_Filter *subf;
  710. switch ( slapi_filter_get_choice( f ) )
  711. {
  712. case LDAP_FILTER_AND:
  713. case LDAP_FILTER_OR:
  714. case LDAP_FILTER_NOT:
  715. /* assign simple filters first */
  716. f->assigned_decoder = 0;
  717. for(subf=f->f_list; subf != NULL; subf = subf->f_next )
  718. ret = index_subsys_assign_decoders(subf);
  719. /* now check for filter grouping opportunities... */
  720. if(slapi_filter_get_choice( f ) != LDAP_FILTER_NOT)
  721. index_subsys_group_decoders(f);
  722. else
  723. {
  724. /* LDAP_FILTER_NOT is a special case
  725. * the contained sub-filter determines
  726. * the assigned index - the index plugin has
  727. * the option to refuse to service the
  728. * NOT filter when it is presented
  729. */
  730. f->assigned_decoder = f->f_list->assigned_decoder;
  731. }
  732. break;
  733. default:
  734. /* find a decoder that fits this simple filter */
  735. ret = index_subsys_assign_decoder(f);
  736. }
  737. return ret;
  738. }
  739. /* index_subsys_decoder_done
  740. * -------------------------
  741. * recurses through complex filters
  742. * removing decoders
  743. */
  744. static int index_subsys_decoder_done(Slapi_Filter *f)
  745. {
  746. int ret = 0;
  747. Slapi_Filter *subf;
  748. indexEntry *index;
  749. indexEntry *next_index;
  750. switch ( slapi_filter_get_choice( f ) )
  751. {
  752. case LDAP_FILTER_AND:
  753. case LDAP_FILTER_OR:
  754. case LDAP_FILTER_NOT:
  755. /* remove simple filters first */
  756. for(subf=f->f_list; subf != NULL; subf = subf->f_next )
  757. ret = index_subsys_decoder_done(subf);
  758. break;
  759. default:
  760. /* free the decoders - shallow free */
  761. index = f->assigned_decoder;
  762. while(index)
  763. {
  764. next_index = index->list.pNext;
  765. slapi_ch_free((void**)index);
  766. index = next_index;
  767. }
  768. f->assigned_decoder = 0;
  769. }
  770. return ret;
  771. }
  772. /* index_subsys_evaluate_filter
  773. * ----------------------------
  774. * passes the filter to the correct plugin
  775. * index_subsys_assign_filter_decoders() must
  776. * have been called previously on this filter
  777. * this function can be safely called on all
  778. * filters post index_subsys_assign_filter_decoders()
  779. * whether they are assigned to a plugin or not
  780. *
  781. * returns:
  782. * INDEX_FILTER_EVALUTED: a candidate list is produced
  783. * INDEX_FILTER_UNEVALUATED: filter not considered
  784. */
  785. int index_subsys_evaluate_filter(Slapi_Filter *f, Slapi_DN *namespace_dn, IndexEntryList **out)
  786. {
  787. int ret = INDEX_FILTER_UNEVALUATED;
  788. indexEntry *index = (indexEntry*)f->assigned_decoder;
  789. if(index && theCache)
  790. {
  791. index_subsys_read_lock();
  792. /* there is a list of indexes which may
  793. * provide an answer for this filter, we
  794. * need to invoke the first one that matches
  795. * the namespace requested
  796. */
  797. for(; index; index = index->list.pNext)
  798. {
  799. /* check namespace */
  800. if(slapi_sdn_compare(index->namespace_dn, namespace_dn))
  801. {
  802. /* wrong namespace */
  803. continue;
  804. }
  805. /* execute the search */
  806. if(index->lookup_func)
  807. {
  808. ret = (index->lookup_func)(f, out, index->user_data);
  809. break;
  810. }
  811. }
  812. index_subsys_unlock();
  813. }
  814. return ret;
  815. }
  816. /* slapi_index_register_decoder
  817. * ----------------------------
  818. * This allows a decoder to register itself,
  819. * it also builds the initial cache when first
  820. * called. Note, there is no way to deregister
  821. * once registered - this allows a lock free cache
  822. * at the expense of a restart to clear old
  823. * indexes, this shouldnt be a problem since it is
  824. * not expected that indexes will be removed
  825. * often.
  826. */
  827. int slapi_index_register_decoder(char *plugin_id, index_validate_callback validate_op)
  828. {
  829. static int firstTime = 1;
  830. static int gotIDLapi = 0;
  831. int ret = 0;
  832. indexPlugin *plg;
  833. if(firstTime)
  834. {
  835. /* create the cache */
  836. theCache = (globalIndexCache*)slapi_ch_malloc(sizeof(globalIndexCache));
  837. if(theCache)
  838. {
  839. theCache->pPlugins = 0;
  840. theCache->ppIndexIndex = 0;
  841. theCache->index_count = 0;
  842. theCache->cache_lock = slapi_new_rwlock();
  843. firstTime = 0;
  844. if(!gotIDLapi)
  845. {
  846. if(slapi_apib_get_interface(IDL_v1_0_GUID, &idl_api))
  847. {
  848. gotIDLapi = 1;
  849. }
  850. }
  851. }
  852. else
  853. {
  854. ret = -1;
  855. goto bail;
  856. }
  857. }
  858. index_subsys_write_lock();
  859. /* add the index decoder to the cache - no checks, better register once only*/
  860. plg = (indexPlugin*)slapi_ch_malloc(sizeof(indexPlugin));
  861. if(plg)
  862. {
  863. plg->id = slapi_ch_strdup(plugin_id);
  864. plg->indexes = 0;
  865. plg->validate_op = validate_op;
  866. /* we always add to the start of the linked list */
  867. plg->list.pPrev = 0;
  868. if(theCache->pPlugins)
  869. {
  870. plg->list.pNext = theCache->pPlugins;
  871. theCache->pPlugins->list.pPrev = plg;
  872. }
  873. else
  874. plg->list.pNext = 0;
  875. theCache->pPlugins = plg;
  876. }
  877. else
  878. ret = -1;
  879. index_subsys_unlock();
  880. bail:
  881. return ret;
  882. }
  883. /* slapi_index_register_index
  884. * --------------------------
  885. * a plugin that has registered itself may
  886. * then proceed to register individual indexes
  887. * that it looks after. This function adds
  888. * the indexes to the plugin cache.
  889. */
  890. int slapi_index_register_index(char *plugin_id, indexed_item *registration_item, void *user_data)
  891. {
  892. int ret = 0;
  893. indexPlugin *plg;
  894. indexEntry *index;
  895. int a_matched_index = 0;
  896. Slapi_Filter *tmp_f = slapi_str2filter(registration_item->index_filter);
  897. Slapi_Backend *be;
  898. if(!theCache || !tmp_f)
  899. return -1;
  900. index_subsys_write_lock();
  901. /* first lets find the plugin */
  902. plg = theCache->pPlugins;
  903. while(plg)
  904. {
  905. if(!slapi_UTF8CASECMP(plugin_id, plg->id))
  906. {
  907. /* found plugin */
  908. break;
  909. }
  910. plg = plg->list.pNext;
  911. }
  912. if(0 == plg)
  913. {
  914. /* not found */
  915. ret = -1;
  916. goto bail;
  917. }
  918. /* map the namespace dn to a backend dn */
  919. be = slapi_be_select( registration_item->namespace_dn );
  920. if(be == defbackend_get_backend())
  921. {
  922. ret = -1;
  923. goto bail;
  924. }
  925. /* now add the new index - we shall assume indexes
  926. * will not be registered twice by different plugins,
  927. * in that event, the last one added wins
  928. * the first matching index in the list is always
  929. * the current one, other matching indexes are ignored
  930. * therefore reregistering an index with NULL
  931. * callbacks disables the index for that plugin
  932. */
  933. /* find the index if already registered */
  934. index = plg->indexes;
  935. while(index)
  936. {
  937. if(index_subsys_index_matches_filter(index, tmp_f))
  938. {
  939. /* found it - free what is currently there, it will be replaced */
  940. slapi_ch_free((void**)&index->indexfilterstr);
  941. slapi_filter_free(index->indexfilter, 1);
  942. slapi_ch_free((void**)&index->indexedAttribute);
  943. charray_free( index->associated_attrs );
  944. index->associated_attrs = 0;
  945. a_matched_index = 1;
  946. break;
  947. }
  948. index = index->list.pNext;
  949. }
  950. if(!index)
  951. index = (indexEntry*)slapi_ch_calloc(1,sizeof(indexEntry));
  952. index->indexfilterstr = slapi_ch_strdup(registration_item->index_filter);
  953. index->indexfilter = tmp_f;
  954. index->lookup_func = registration_item->search_op;
  955. index->user_data = user_data;
  956. index->namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
  957. /* for now, we support simple filters only */
  958. index->indexedAttribute = slapi_ch_strdup(index->indexfilter->f_type);
  959. /* add associated attributes */
  960. if(registration_item->associated_attrs)
  961. {
  962. index->associated_attrs =
  963. cool_charray_dup( registration_item->associated_attrs );
  964. }
  965. if(!a_matched_index)
  966. {
  967. if(plg->indexes)
  968. {
  969. index->list.pNext = plg->indexes;
  970. plg->indexes->list.pPrev = plg;
  971. }
  972. else
  973. index->list.pNext = 0;
  974. index->list.pPrev = 0;
  975. plg->indexes = index;
  976. theCache->index_count++;
  977. }
  978. /* now we need to rebuild the index (onto the indexed items)
  979. * this is a bit inefficient since
  980. * every new index that is added triggers
  981. * an index rebuild - but this is countered
  982. * by the fact this will probably happen once
  983. * at start up most of the time, and very rarely
  984. * otherwise, so normal server performance should
  985. * not be unduly effected effected
  986. * we take care to build the index and only then swap it in
  987. * for the old one
  988. * PARPAR: we need to RW (or maybe a ref count) lock here
  989. * only alternative would be to not have an index :(
  990. * for few plugins with few indexes thats a possibility
  991. * traditionally many indexes have not been a good idea
  992. * anyway so...
  993. */
  994. /* indexIndex = (indexEntry**)slapi_ch_malloc(sizeof(indexEntry*) * (theCache->index_count+1));
  995. */
  996. /* for now, lets see how fast things are without an index
  997. * that should not be a problem at all to begin with since
  998. * presence will be the only index decoder. Additionally,
  999. * adding an index means we need locks - um, no.
  1000. * so no more to do
  1001. */
  1002. bail:
  1003. index_subsys_unlock();
  1004. return ret;
  1005. }
  1006. /* index_subsys_index_matches_index
  1007. * --------------------------------
  1008. * criteria for a match is that the types
  1009. * are the same and that all the associated
  1010. * attributes that are configured for cmp_to
  1011. * are also in cmp_with.
  1012. */
  1013. int index_subsys_index_matches_index(indexEntry *cmp_to, indexEntry *cmp_with)
  1014. {
  1015. int ret = 0;
  1016. if(slapi_attr_types_equivalent(cmp_to->indexedAttribute, cmp_with->indexedAttribute))
  1017. {
  1018. /* now check associated */
  1019. if(cmp_to->associated_attrs)
  1020. {
  1021. if(cmp_with->associated_attrs)
  1022. {
  1023. int x,y;
  1024. ret = 1;
  1025. for(x=0; cmp_to->associated_attrs[x] && ret == 1; x++)
  1026. {
  1027. ret = 0;
  1028. for(y=0; cmp_with->associated_attrs[y]; y++)
  1029. {
  1030. if(slapi_attr_types_equivalent(
  1031. cmp_to->associated_attrs[x],
  1032. cmp_with->associated_attrs[y]
  1033. ))
  1034. {
  1035. /* matched on associated attribute */
  1036. ret = 1;
  1037. break;
  1038. }
  1039. }
  1040. }
  1041. }
  1042. }
  1043. else
  1044. {
  1045. /* no associated is an auto match */
  1046. ret = 1;
  1047. }
  1048. }
  1049. return ret;
  1050. }
  1051. indexEntry *index_subsys_index_shallow_dup(indexEntry *dup_this)
  1052. {
  1053. indexEntry *ret = (indexEntry *)slapi_ch_calloc(1,sizeof(indexEntry));
  1054. /* shallow copy - dont copy linked list pointers */
  1055. ret->indexedAttribute = dup_this->indexedAttribute;
  1056. ret->indexfilter = dup_this->indexfilter;
  1057. ret->indexfilterstr = dup_this->indexfilterstr;
  1058. ret->user_data = dup_this->user_data;
  1059. ret->namespace_dn = dup_this->namespace_dn;
  1060. ret->lookup_func = dup_this->lookup_func;
  1061. ret->associated_attrs = dup_this->associated_attrs;
  1062. return ret;
  1063. }
  1064. /* index_subsys_assign_decoder
  1065. * ---------------------------
  1066. * finds a decoder which will service
  1067. * the filter if one is available and assigns
  1068. * the decoder to the filter. Currently this
  1069. * function supports only simple filters, but
  1070. * may in the future support complex filter
  1071. * assignment (possibly including filter rewriting
  1072. * to make more matches possible)
  1073. *
  1074. * populates f->alternate_decoders if more than one
  1075. * index could deal with a filter - only filters that
  1076. * have a match with all associated attributes of the
  1077. * first found filter are said to match - their
  1078. * namespaces may be different
  1079. */
  1080. static int index_subsys_assign_decoder(Slapi_Filter *f)
  1081. {
  1082. int ret = 0; /* always succeed */
  1083. indexPlugin *plg;
  1084. indexEntry *index = 0;
  1085. indexEntry *last = 0;
  1086. f->assigned_decoder = 0;
  1087. if(!theCache)
  1088. return 0;
  1089. index_subsys_read_lock();
  1090. plg = theCache->pPlugins;
  1091. while(plg)
  1092. {
  1093. index = plg->indexes;
  1094. while(index)
  1095. {
  1096. if(INDEX_MATCH_NONE != index_subsys_index_matches_filter(index, f))
  1097. {
  1098. /* we have a match, assign this decoder if not disabled */
  1099. if(index->lookup_func)
  1100. {
  1101. if(!f->assigned_decoder)
  1102. {
  1103. f->assigned_decoder = index_subsys_index_shallow_dup(index);
  1104. last = f->assigned_decoder;
  1105. }
  1106. else
  1107. {
  1108. /* add to alternate list - we require that they all
  1109. * have the same associated attributes configuration for now
  1110. * though they may have different namespaces
  1111. */
  1112. if(index_subsys_index_matches_index(f->assigned_decoder, index))
  1113. {
  1114. /* add to end */
  1115. last->list.pNext = index_subsys_index_shallow_dup(index);
  1116. last = last->list.pNext;
  1117. }
  1118. }
  1119. }
  1120. else
  1121. {
  1122. /* index disabled, so we must allow another plugin to
  1123. * get a crack at servicing the index
  1124. */
  1125. break;
  1126. }
  1127. }
  1128. index = index->list.pNext;
  1129. }
  1130. plg = plg->list.pNext;
  1131. }
  1132. index_subsys_unlock();
  1133. return ret;
  1134. }