vlv_srch.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* vlv_srch.c */
  42. #include "back-ldbm.h"
  43. #include "vlv_srch.h"
  44. /* Attributes for vlvSearch */
  45. char* const type_vlvName = "cn";
  46. char* const type_vlvBase = "vlvBase";
  47. char* const type_vlvScope = "vlvScope";
  48. char* const type_vlvFilter = "vlvFilter";
  49. /* Attributes for vlvIndex */
  50. char* const type_vlvSort = "vlvSort";
  51. char* const type_vlvFilename = "vlvFilename";
  52. char* const type_vlvEnabled = "vlvEnabled";
  53. char* const type_vlvUses = "vlvUses";
  54. static const char *file_prefix= "vlv#"; /* '#' used to avoid collision with real attributes */
  55. static const char *file_suffix= LDBM_FILENAME_SUFFIX;
  56. static int vlvIndex_createfilename(struct vlvIndex* pIndex, char **ppc);
  57. static int vlvIndex_equal(const struct vlvIndex* p1, const sort_spec* sort_control);
  58. static void vlvIndex_checkforindex(struct vlvIndex* p, backend *be);
  59. /*
  60. * Create a new vlvSearch object
  61. */
  62. struct vlvSearch*
  63. vlvSearch_new()
  64. {
  65. struct vlvSearch* p = (struct vlvSearch*)slapi_ch_calloc(1,sizeof(struct vlvSearch));
  66. if(p!=NULL)
  67. {
  68. p->vlv_e= NULL;
  69. p->vlv_dn= NULL;
  70. p->vlv_name= NULL;
  71. p->vlv_base= NULL;
  72. p->vlv_scope= LDAP_SCOPE_BASE;
  73. p->vlv_filter= NULL;
  74. p->vlv_slapifilter= NULL;
  75. p->vlv_index= NULL;
  76. p->vlv_next= NULL;
  77. }
  78. return p;
  79. }
  80. /*
  81. * Trim spaces off the end of the string
  82. */
  83. static void
  84. trimspaces(char *s)
  85. {
  86. if (s) {
  87. PRUint32 i= strlen(s) - 1;
  88. while(i > 0 && isascii(s[i]) && isspace(s[i]))
  89. {
  90. s[i]= '\0';
  91. i--;
  92. }
  93. }
  94. }
  95. /*
  96. * Re-Initialise a vlvSearch object
  97. */
  98. void
  99. vlvSearch_reinit(struct vlvSearch* p, const struct backentry *base)
  100. {
  101. if (p->vlv_initialized) {
  102. return; /* no work to do */
  103. }
  104. if (LDAP_SCOPE_ONELEVEL != p->vlv_scope) {
  105. /* Only kind we re-init is onelevel searches */
  106. return;
  107. }
  108. /* Now down to work */
  109. if (NULL != p->vlv_slapifilter) {
  110. slapi_filter_free(p->vlv_slapifilter,1);
  111. }
  112. p->vlv_slapifilter= slapi_str2filter( p->vlv_filter );
  113. filter_normalize(p->vlv_slapifilter);
  114. /* make (&(parentid=idofbase)(|(originalfilter)(objectclass=referral))) */
  115. {
  116. Slapi_Filter *fid2kids= NULL;
  117. Slapi_Filter *focref= NULL;
  118. Slapi_Filter *fand= NULL;
  119. Slapi_Filter *forr= NULL;
  120. p->vlv_slapifilter= create_onelevel_filter(p->vlv_slapifilter, base, 0 /* managedsait */, &fid2kids, &focref, &fand, &forr);
  121. }
  122. }
  123. /*
  124. * Initialise a vlvSearch object
  125. */
  126. void
  127. vlvSearch_init(struct vlvSearch* p, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm_instance *inst)
  128. {
  129. /* VLV specification */
  130. /* Need to copy the entry here because this one is in the cache,
  131. * not forever ! */
  132. p->vlv_e= slapi_entry_dup( e );
  133. p->vlv_dn= slapi_sdn_dup(slapi_entry_get_sdn_const(e));
  134. p->vlv_name= slapi_entry_attr_get_charptr(e,type_vlvName);
  135. p->vlv_base= slapi_sdn_new_dn_passin(slapi_entry_attr_get_charptr(e,type_vlvBase));
  136. p->vlv_scope= slapi_entry_attr_get_int(e,type_vlvScope);
  137. p->vlv_filter= slapi_entry_attr_get_charptr(e,type_vlvFilter);
  138. p->vlv_initialized = 1;
  139. /* JCM: Should perform some validation and report errors to the error log */
  140. /* JCM: Add brackets around the filter if none are there... */
  141. trimspaces(p->vlv_name);
  142. trimspaces(p->vlv_filter);
  143. if(strlen(p->vlv_filter)>0)
  144. {
  145. /* Convert the textual filter, into a Slapi_Filter structure */
  146. p->vlv_slapifilter= slapi_str2filter( p->vlv_filter );
  147. filter_normalize(p->vlv_slapifilter);
  148. }
  149. /* JCM: Really should convert the slapifilter into a string and use that. */
  150. /* Convert the filter based on the scope of the search */
  151. switch(p->vlv_scope)
  152. {
  153. case LDAP_SCOPE_BASE:
  154. /* Don't need to alter the filter */
  155. break;
  156. case LDAP_SCOPE_ONELEVEL:
  157. {
  158. /*
  159. * Get the base object for the search.
  160. * The entry "" will never be contained in the database,
  161. * so treat it as a special case.
  162. */
  163. struct backentry *e= NULL;
  164. if ( !slapi_sdn_isempty(p->vlv_base)) {
  165. Slapi_Backend *oldbe = NULL;
  166. entry_address addr;
  167. /* switch context to the target backend */
  168. slapi_pblock_get(pb, SLAPI_BACKEND, &oldbe);
  169. slapi_pblock_set(pb, SLAPI_BACKEND, inst->inst_be);
  170. slapi_pblock_set(pb, SLAPI_PLUGIN, inst->inst_be->be_database);
  171. addr.dn = (char*)slapi_sdn_get_ndn (p->vlv_base);
  172. addr.uniqueid = NULL;
  173. e = find_entry( pb, inst->inst_be, &addr, NULL );
  174. /* Check to see if the entry is absent. If it is, mark this search
  175. * as not initialized */
  176. if (NULL == e) {
  177. p->vlv_initialized = 0;
  178. /* We crash on anyhow, and rely on the fact that the filter
  179. * we create is bogus to prevent chaos */
  180. }
  181. /* switch context back to the DSE backend */
  182. slapi_pblock_set(pb, SLAPI_BACKEND, oldbe);
  183. slapi_pblock_set(pb, SLAPI_PLUGIN, oldbe->be_database);
  184. }
  185. /* make (&(parentid=idofbase)(|(originalfilter)(objectclass=referral))) */
  186. {
  187. Slapi_Filter *fid2kids= NULL;
  188. Slapi_Filter *focref= NULL;
  189. Slapi_Filter *fand= NULL;
  190. Slapi_Filter *forr= NULL;
  191. p->vlv_slapifilter= create_onelevel_filter(p->vlv_slapifilter, e, 0 /* managedsait */, &fid2kids, &focref, &fand, &forr);
  192. /* jcm: fid2kids, focref, fand, and forr get freed when we free p->vlv_slapifilter */
  193. cache_return(&inst->inst_cache,&e);
  194. }
  195. }
  196. break;
  197. case LDAP_SCOPE_SUBTREE:
  198. {
  199. /* make (|(originalfilter)(objectclass=referral))) */
  200. /* No need for scope-filter since we apply a scope test before the filter test */
  201. Slapi_Filter *focref= NULL;
  202. Slapi_Filter *forr= NULL;
  203. p->vlv_slapifilter= create_subtree_filter(p->vlv_slapifilter, 0 /* managedsait */, &focref, &forr);
  204. /* jcm: focref and forr get freed when we free p->vlv_slapifilter */
  205. }
  206. break;
  207. }
  208. }
  209. /*
  210. * Destroy an existing vlvSearch object
  211. */
  212. void
  213. vlvSearch_delete(struct vlvSearch** ppvs)
  214. {
  215. if(ppvs!=NULL && *ppvs!=NULL)
  216. {
  217. struct vlvIndex *pi, *ni;
  218. slapi_sdn_free(&((*ppvs)->vlv_dn));
  219. slapi_ch_free((void**)&((*ppvs)->vlv_name));
  220. slapi_sdn_free(&((*ppvs)->vlv_base));
  221. slapi_ch_free((void**)&((*ppvs)->vlv_filter));
  222. slapi_filter_free((*ppvs)->vlv_slapifilter,1);
  223. for(pi= (*ppvs)->vlv_index;pi!=NULL;)
  224. {
  225. ni= pi->vlv_next;
  226. if(pi->vlv_be != NULL) {
  227. vlvIndex_go_offline(pi,pi->vlv_be);
  228. }
  229. vlvIndex_delete(&pi);
  230. pi= ni;
  231. }
  232. slapi_ch_free((void**)ppvs);
  233. *ppvs= NULL;
  234. }
  235. }
  236. /*
  237. * Add a search to a list.
  238. *
  239. * We add it to the end of the list because there could
  240. * be other threads traversing the list at this time.
  241. */
  242. void
  243. vlvSearch_addtolist(struct vlvSearch* p, struct vlvSearch** pplist)
  244. {
  245. if(pplist!=NULL && p!=NULL)
  246. {
  247. p->vlv_next= NULL;
  248. if(*pplist==NULL)
  249. {
  250. *pplist= p;
  251. }
  252. else
  253. {
  254. struct vlvSearch* last= *pplist;
  255. for(;last->vlv_next!=NULL;last=last->vlv_next);
  256. last->vlv_next= p;
  257. }
  258. }
  259. }
  260. /*
  261. * Compare two VLV Searches to see if they're the same, based on their VLV Search specification.
  262. */
  263. static struct vlvIndex *
  264. vlvSearch_equal(const struct vlvSearch* p1, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control)
  265. {
  266. struct vlvIndex *pi= NULL;
  267. int r= (slapi_sdn_compare(p1->vlv_base,base)==0);
  268. if(r) r= (p1->vlv_scope==scope);
  269. if(r) r= (strcasecmp(p1->vlv_filter,filter)==0);
  270. if(r)
  271. {
  272. pi= p1->vlv_index;
  273. r= 0;
  274. for(;!r && pi!=NULL;)
  275. {
  276. r= vlvIndex_equal(pi, sort_control);
  277. if(!r)
  278. {
  279. pi= pi->vlv_next;
  280. }
  281. }
  282. }
  283. return pi;
  284. }
  285. /*
  286. * Find an enabled VLV Search in a list which matches the
  287. * description provided in "base, scope, filter, sort_control"
  288. */
  289. struct vlvIndex*
  290. vlvSearch_findenabled(backend *be,struct vlvSearch* plist, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control)
  291. {
  292. struct vlvSearch *t= plist;
  293. struct vlvIndex *pi= NULL;
  294. for(; (t!=NULL) && (pi == NULL); t= t->vlv_next)
  295. {
  296. pi= vlvSearch_equal(t,base,scope,filter,sort_control);
  297. if(pi!=NULL)
  298. {
  299. if(!vlvIndex_enabled(pi))
  300. {
  301. /*
  302. * A VLV Spec which matched the search criteria was found.
  303. * But it hasn't been enabled yet. Check to see if the
  304. * index is there. But, only check once every 60 seconds.
  305. */
  306. time_t curtime = current_time();
  307. if(curtime>pi->vlv_lastchecked+60)
  308. {
  309. vlvIndex_checkforindex(pi, be);
  310. pi->vlv_lastchecked= current_time();
  311. }
  312. }
  313. if(!vlvIndex_enabled(pi))
  314. {
  315. pi= NULL;
  316. }
  317. }
  318. }
  319. return pi;
  320. }
  321. /*
  322. * Find a VLV Search in a list which matches the name
  323. */
  324. struct vlvIndex*
  325. vlvSearch_findname(const struct vlvSearch* plist, const char *name)
  326. {
  327. const struct vlvSearch* t= plist;
  328. for(; t!=NULL ; t= t->vlv_next)
  329. {
  330. struct vlvIndex *pi= t->vlv_index;
  331. for(;pi!=NULL;pi= pi->vlv_next)
  332. {
  333. if(strcasecmp(pi->vlv_name,name)==0)
  334. {
  335. return pi;
  336. }
  337. }
  338. }
  339. return NULL;
  340. }
  341. /*
  342. * Find a VLV Search in a list which matches the index name
  343. */
  344. struct vlvIndex*
  345. vlvSearch_findindexname(const struct vlvSearch* plist, const char *name)
  346. {
  347. const struct vlvSearch* t= plist;
  348. for(; t!=NULL ; t= t->vlv_next)
  349. {
  350. struct vlvIndex *pi= t->vlv_index;
  351. for(;pi!=NULL;pi= pi->vlv_next)
  352. {
  353. if(strcasecmp(pi->vlv_attrinfo->ai_type,name)==0)
  354. {
  355. return pi;
  356. }
  357. }
  358. }
  359. return NULL;
  360. }
  361. /*
  362. * Get a list of VLV Index names.
  363. * The returned pointer must be freed with slapi_ch_free
  364. */
  365. char *
  366. vlvSearch_getnames(const struct vlvSearch* plist)
  367. {
  368. /* Work out how long the string will be */
  369. char *text;
  370. int length= 5; /* enough to hold 'none' */
  371. const struct vlvSearch* t= plist;
  372. for(; t!=NULL ; t= t->vlv_next)
  373. {
  374. struct vlvIndex *pi= t->vlv_index;
  375. for(;pi!=NULL;pi= pi->vlv_next)
  376. {
  377. length+= strlen(pi->vlv_name) + 4;
  378. }
  379. }
  380. /* Build a comma delimited list of Index names */
  381. text= slapi_ch_malloc(length);
  382. if(length==5)
  383. {
  384. strcpy(text,"none");
  385. }
  386. else
  387. {
  388. text[0]= '\0';
  389. t= plist;
  390. for(; t!=NULL ; t= t->vlv_next)
  391. {
  392. struct vlvIndex *pi= t->vlv_index;
  393. for(;pi!=NULL;pi= pi->vlv_next)
  394. {
  395. sprintf(text + strlen(text),"'%s', ",pi->vlv_name);
  396. }
  397. }
  398. }
  399. return text;
  400. }
  401. /*
  402. * Find a VLV Search in a list, based on the DN.
  403. */
  404. struct vlvSearch*
  405. vlvSearch_finddn(const struct vlvSearch* plist, const Slapi_DN *dn)
  406. {
  407. const struct vlvSearch* curr= plist;
  408. for(; curr!=NULL && slapi_sdn_compare(curr->vlv_dn,dn)!=0; curr= curr->vlv_next);
  409. return (struct vlvSearch*)curr;
  410. }
  411. /*
  412. * Remove a VLV Search from a list, based on the DN.
  413. */
  414. void
  415. vlvSearch_removefromlist(struct vlvSearch** pplist, const Slapi_DN *dn)
  416. {
  417. int done= 0;
  418. struct vlvSearch* prev= NULL;
  419. struct vlvSearch* curr= *pplist;
  420. while(curr!=NULL && !done)
  421. {
  422. if(slapi_sdn_compare(curr->vlv_dn,dn)==0)
  423. {
  424. if(curr==*pplist)
  425. {
  426. *pplist= curr->vlv_next;
  427. }
  428. else
  429. {
  430. prev->vlv_next= curr->vlv_next;
  431. }
  432. done= 1;
  433. }
  434. else
  435. {
  436. prev= curr;
  437. curr= curr->vlv_next;
  438. }
  439. }
  440. }
  441. /*
  442. * Access Control Check to see if the client is allowed to use this VLV Search.
  443. */
  444. int
  445. vlvSearch_accessallowed(struct vlvSearch *p, Slapi_PBlock *pb)
  446. {
  447. char *attrs[2] = { NULL, NULL};
  448. attrs[0] = type_vlvName;
  449. return (plugin_call_acl_plugin ( pb, (Slapi_Entry*)p->vlv_e, attrs, NULL,
  450. SLAPI_ACL_READ, ACLPLUGIN_ACCESS_READ_ON_VLV, NULL ) );
  451. }
  452. const Slapi_DN *vlvSearch_getBase(struct vlvSearch* p)
  453. {
  454. return p->vlv_base;
  455. }
  456. int vlvSearch_getScope(struct vlvSearch* p)
  457. {
  458. return p->vlv_scope;
  459. }
  460. Slapi_Filter *vlvSearch_getFilter(struct vlvSearch* p)
  461. {
  462. return p->vlv_slapifilter;
  463. }
  464. int vlvSearch_isVlvSearchEntry(Slapi_Entry *e)
  465. {
  466. return slapi_entry_attr_hasvalue(e, "objectclass", "vlvsearch");
  467. }
  468. void vlvSearch_addIndex(struct vlvSearch *pSearch, struct vlvIndex *pIndex)
  469. {
  470. pIndex->vlv_next= NULL;
  471. if(pSearch->vlv_index==NULL)
  472. {
  473. pSearch->vlv_index= pIndex;
  474. }
  475. else
  476. {
  477. struct vlvIndex* last= pSearch->vlv_index;
  478. for(;last->vlv_next!=NULL;last=last->vlv_next);
  479. last->vlv_next= pIndex;
  480. }
  481. }
  482. /* ============================================================================================== */
  483. /*
  484. * Create a new vlvIndex object
  485. */
  486. struct vlvIndex*
  487. vlvIndex_new()
  488. {
  489. struct vlvIndex* p = (struct vlvIndex*)slapi_ch_calloc(1,sizeof(struct vlvIndex));
  490. if(p!=NULL)
  491. {
  492. p->vlv_sortspec= NULL;
  493. p->vlv_attrinfo= attrinfo_new();
  494. p->vlv_sortkey= NULL;
  495. p->vlv_filename= NULL;
  496. p->vlv_mrpb= NULL;
  497. p->vlv_syntax_plugin= NULL;
  498. p->vlv_indexlength_lock= PR_NewLock();
  499. p->vlv_indexlength_cached= 0;
  500. p->vlv_indexlength= 0;
  501. p->vlv_online = 1;
  502. p->vlv_enabled = 0;
  503. p->vlv_lastchecked= 0;
  504. p->vlv_uses= 0;
  505. p->vlv_search= NULL;
  506. p->vlv_next= NULL;
  507. }
  508. return p;
  509. }
  510. /*
  511. * Destroy an existing vlvIndex object
  512. */
  513. void
  514. vlvIndex_delete(struct vlvIndex** ppvs)
  515. {
  516. if(ppvs!=NULL && *ppvs!=NULL)
  517. {
  518. slapi_ch_free((void**)&((*ppvs)->vlv_sortspec));
  519. {
  520. int n;
  521. for(n=0;(*ppvs)->vlv_sortkey[n]!=NULL;n++)
  522. {
  523. if((*ppvs)->vlv_mrpb[n] != NULL) {
  524. destroy_matchrule_indexer((*ppvs)->vlv_mrpb[n]);
  525. slapi_pblock_destroy((*ppvs)->vlv_mrpb[n]);
  526. }
  527. }
  528. }
  529. internal_ldap_free_sort_keylist((*ppvs)->vlv_sortkey);
  530. attrinfo_delete(&((*ppvs)->vlv_attrinfo));
  531. slapi_ch_free((void**)&((*ppvs)->vlv_name));
  532. slapi_ch_free((void**)&((*ppvs)->vlv_filename));
  533. slapi_ch_free((void**)&((*ppvs)->vlv_mrpb));
  534. slapi_ch_free((void**)&((*ppvs)->vlv_syntax_plugin));
  535. PR_DestroyLock((*ppvs)->vlv_indexlength_lock);
  536. slapi_ch_free((void**)ppvs);
  537. *ppvs= NULL;
  538. }
  539. }
  540. /*
  541. * Initialise a vlvSearch object
  542. */
  543. void
  544. vlvIndex_init(struct vlvIndex* p, backend *be, struct vlvSearch* pSearch, const Slapi_Entry *e)
  545. {
  546. struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
  547. char *filename= NULL;
  548. if (NULL == p)
  549. return;
  550. /* JCM: Should perform some validation and report errors to the error log */
  551. /* JCM: Add brackets around the filter if none are there... */
  552. p->vlv_sortspec= slapi_entry_attr_get_charptr(e,type_vlvSort);
  553. trimspaces(p->vlv_sortspec);
  554. p->vlv_name= slapi_entry_attr_get_charptr(e,type_vlvName);
  555. trimspaces(p->vlv_name);
  556. p->vlv_search= pSearch;
  557. /* Convert the textual sort specification into a keylist structure */
  558. internal_ldap_create_sort_keylist(&(p->vlv_sortkey),p->vlv_sortspec);
  559. {
  560. /*
  561. * For each sort attribute find the appropriate syntax plugin,
  562. * and if it has a matching rule, create a matching rule indexer object.
  563. */
  564. int n;
  565. for(n=0;p->vlv_sortkey[n]!=NULL;n++);
  566. p->vlv_mrpb= (Slapi_PBlock**)slapi_ch_calloc(n+1,sizeof(Slapi_PBlock*));
  567. p->vlv_syntax_plugin= (void **)(Slapi_PBlock**)slapi_ch_calloc(n+1,sizeof(Slapi_PBlock*));
  568. for(n=0;p->vlv_sortkey[n]!=NULL;n++)
  569. {
  570. slapi_attr_type2plugin( p->vlv_sortkey[n]->sk_attrtype, &p->vlv_syntax_plugin[n] );
  571. if(p->vlv_sortkey[n]->sk_matchruleoid!=NULL)
  572. {
  573. create_matchrule_indexer(&p->vlv_mrpb[n],p->vlv_sortkey[n]->sk_matchruleoid,p->vlv_sortkey[n]->sk_attrtype);
  574. }
  575. }
  576. }
  577. /* Create an index filename for the search */
  578. if(vlvIndex_createfilename(p,&filename))
  579. {
  580. p->vlv_filename= slapi_ch_smprintf("%s%s%s",file_prefix,filename,file_suffix);
  581. /* Create an attrinfo structure */
  582. p->vlv_attrinfo->ai_type= slapi_ch_smprintf("%s%s",file_prefix,filename);
  583. p->vlv_attrinfo->ai_indexmask= INDEX_VLV;
  584. /* Check if the index file actually exists */
  585. if(li!=NULL)
  586. {
  587. vlvIndex_checkforindex(p, be);
  588. }
  589. p->vlv_lastchecked= current_time();
  590. }
  591. slapi_ch_free((void**)&filename);
  592. }
  593. /*
  594. * Determine how many {key,data} pairs there are in the VLV Index.
  595. * We only work out the length of the index once, then we cache
  596. * it and maintain it.
  597. */
  598. PRUint32
  599. vlvIndex_get_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
  600. {
  601. if (NULL == p)
  602. return 0;
  603. if(!p->vlv_indexlength_cached)
  604. {
  605. DBC *dbc = NULL;
  606. DB_TXN *db_txn = NULL;
  607. int err= 0;
  608. if (NULL != txn)
  609. {
  610. db_txn = txn->back_txn_txn;
  611. }
  612. err = db->cursor(db, db_txn, &dbc, 0);
  613. if(err==0)
  614. {
  615. DBT key= {0};
  616. DBT data= {0};
  617. key.flags= DB_DBT_MALLOC;
  618. data.flags= DB_DBT_MALLOC;
  619. err= dbc->c_get(dbc,&key,&data,DB_LAST);
  620. if(err==0)
  621. {
  622. slapi_ch_free(&(key.data));
  623. slapi_ch_free(&(data.data));
  624. err= dbc->c_get(dbc,&key,&data,DB_GET_RECNO);
  625. if(err==0)
  626. {
  627. PR_Lock(p->vlv_indexlength_lock);
  628. p->vlv_indexlength_cached= 1;
  629. p->vlv_indexlength= *((db_recno_t*)data.data);
  630. PR_Unlock(p->vlv_indexlength_lock);
  631. slapi_ch_free(&(data.data));
  632. }
  633. }
  634. dbc->c_close(dbc);
  635. }
  636. else
  637. {
  638. /* couldn't get cursor??? */
  639. }
  640. }
  641. return p->vlv_indexlength;
  642. }
  643. /*
  644. * Increment the index length count.
  645. * We keep track of the index length for efficiency.
  646. */
  647. void
  648. vlvIndex_increment_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
  649. {
  650. if (NULL == p)
  651. return;
  652. if(p->vlv_indexlength_cached)
  653. {
  654. PR_Lock(p->vlv_indexlength_lock);
  655. p->vlv_indexlength++;
  656. PR_Unlock(p->vlv_indexlength_lock);
  657. }
  658. else
  659. {
  660. p->vlv_indexlength= vlvIndex_get_indexlength(p, db, txn);
  661. }
  662. }
  663. /*
  664. * Decrement the index length count.
  665. * We keep track of the index length for efficiency.
  666. */
  667. void
  668. vlvIndex_decrement_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
  669. {
  670. if (NULL == p)
  671. return;
  672. if(p->vlv_indexlength_cached)
  673. {
  674. /* jcm: Check for underflow? */
  675. PR_Lock(p->vlv_indexlength_lock);
  676. p->vlv_indexlength--;
  677. PR_Unlock(p->vlv_indexlength_lock);
  678. }
  679. else
  680. {
  681. p->vlv_indexlength= vlvIndex_get_indexlength(p, db, txn);
  682. }
  683. }
  684. /*
  685. * Increment the usage counter
  686. */
  687. void
  688. vlvIndex_incrementUsage(struct vlvIndex* p)
  689. {
  690. if (NULL == p)
  691. return;
  692. p->vlv_uses++;
  693. }
  694. /*
  695. * Get the filename of the index.
  696. */
  697. const char *
  698. vlvIndex_filename(const struct vlvIndex* p)
  699. {
  700. if (NULL == p)
  701. return NULL;
  702. return p->vlv_filename;
  703. }
  704. /*
  705. * Check if the index is available.
  706. */
  707. int vlvIndex_enabled(const struct vlvIndex* p)
  708. {
  709. if (NULL == p)
  710. return 0;
  711. return p->vlv_enabled;
  712. }
  713. int vlvIndex_online(const struct vlvIndex *p)
  714. {
  715. if (NULL == p)
  716. return 0;
  717. return p->vlv_online;
  718. }
  719. void vlvIndex_go_offline(struct vlvIndex *p, backend *be)
  720. {
  721. if (NULL == p)
  722. return;
  723. p->vlv_online = 0;
  724. p->vlv_enabled = 0;
  725. p->vlv_indexlength = 0;
  726. p->vlv_attrinfo->ai_indexmask |= INDEX_OFFLINE;
  727. dblayer_erase_index_file_nolock(be, p->vlv_attrinfo, 1 /* chkpt if not busy */);
  728. }
  729. void vlvIndex_go_online(struct vlvIndex *p, backend *be)
  730. {
  731. if (NULL == p)
  732. return;
  733. p->vlv_attrinfo->ai_indexmask &= ~INDEX_OFFLINE;
  734. p->vlv_online = 1;
  735. vlvIndex_checkforindex(p, be);
  736. }
  737. /*
  738. * Access Control Check to see if the client is allowed to use this VLV Index.
  739. */
  740. int
  741. vlvIndex_accessallowed(struct vlvIndex *p, Slapi_PBlock *pb)
  742. {
  743. if (NULL == p)
  744. return 0;
  745. return vlvSearch_accessallowed(p->vlv_search, pb);
  746. }
  747. const Slapi_DN *vlvIndex_getBase(struct vlvIndex* p)
  748. {
  749. if (NULL == p)
  750. return NULL;
  751. return vlvSearch_getBase(p->vlv_search);
  752. }
  753. int vlvIndex_getScope(struct vlvIndex* p)
  754. {
  755. if (NULL == p)
  756. return 0;
  757. return vlvSearch_getScope(p->vlv_search);
  758. }
  759. Slapi_Filter *vlvIndex_getFilter(struct vlvIndex* p)
  760. {
  761. if (NULL == p)
  762. return NULL;
  763. return vlvSearch_getFilter(p->vlv_search);
  764. }
  765. const char *vlvIndex_getName(struct vlvIndex* p)
  766. {
  767. if (NULL == p)
  768. return NULL;
  769. return p->vlv_name;
  770. }
  771. /*
  772. * JCM: Could also match reverse sense of index and use in reverse.
  773. */
  774. static int
  775. vlvIndex_equal(const struct vlvIndex* p1, const sort_spec* sort_control)
  776. {
  777. int r= 1;
  778. const sort_spec *t1= sort_control;
  779. LDAPsortkey *t2= p1->vlv_sortkey[0];
  780. int n= 1;
  781. for(;t1!=NULL && t2!=NULL && r;t1= t1->next,t2=p1->vlv_sortkey[n],n++)
  782. {
  783. r= (t1->order && t2->sk_reverseorder) || (!t1->order && !t2->sk_reverseorder);
  784. if(r) r= (strcasecmp(t1->type, t2->sk_attrtype)==0);
  785. if(r)
  786. {
  787. if(t1->matchrule==NULL && t2->sk_matchruleoid==NULL)
  788. {
  789. r= 1;
  790. }
  791. else if(t1->matchrule!=NULL && t2->sk_matchruleoid!=NULL)
  792. {
  793. r= (strcasecmp(t1->matchrule, t2->sk_matchruleoid)==0);
  794. }
  795. else
  796. {
  797. r= 0;
  798. }
  799. }
  800. }
  801. if(r) r= (t1==NULL && t2==NULL);
  802. return r;
  803. }
  804. /*
  805. * Check if the index file actually exists,
  806. * and set vlv_enabled appropriately
  807. */
  808. static void
  809. vlvIndex_checkforindex(struct vlvIndex* p, backend *be)
  810. {
  811. DB *db = NULL;
  812. /* if the vlv index is offline (being generated), don't even look */
  813. if (! p->vlv_online)
  814. return;
  815. if (dblayer_get_index_file(be, p->vlv_attrinfo, &db, 0) == 0) {
  816. p->vlv_enabled = 1;
  817. dblayer_release_index_file( be, p->vlv_attrinfo, db );
  818. } else {
  819. p->vlv_enabled = 0;
  820. }
  821. }
  822. int vlvIndex_isVlvIndexEntry(Slapi_Entry *e)
  823. {
  824. return slapi_entry_attr_hasvalue(e, "objectclass", "vlvindex");
  825. }
  826. /*
  827. * Create the filename for the index.
  828. * Extract all the alphanumeric characters from the descriptive name.
  829. * Convert to all lower case.
  830. */
  831. static int
  832. vlvIndex_createfilename(struct vlvIndex* pIndex, char **ppc)
  833. {
  834. int filenameValid= 1;
  835. unsigned int i;
  836. char *p, *filename;
  837. filename= slapi_ch_malloc(strlen(pIndex->vlv_name) + 1);
  838. p= filename;
  839. for(i=0;i<strlen(pIndex->vlv_name);i++)
  840. {
  841. if(isalnum(pIndex->vlv_name[i]))
  842. {
  843. *p= TOLOWER( pIndex->vlv_name[i] );
  844. p++;
  845. }
  846. }
  847. *p= '\0';
  848. if(strlen(filename)==0)
  849. {
  850. LDAPDebug( LDAP_DEBUG_ANY, "Couldn't generate valid filename from Virtual List View Index Name (%s). Need some alphabetical characters.\n", pIndex->vlv_name, 0, 0);
  851. filenameValid= 0;
  852. }
  853. /* JCM: Check if this file clashes with another VLV Index filename */
  854. *ppc= filename;
  855. return filenameValid;
  856. }
  857. int
  858. vlv_isvlv(char *filename)
  859. {
  860. if (0 == strncmp(filename, file_prefix, 4))
  861. return 1;
  862. return 0;
  863. }
  864. void
  865. internal_ldap_free_sort_keylist(LDAPsortkey **sortKeyList)
  866. {
  867. #if defined(USE_OPENLDAP)
  868. ldap_free_sort_keylist((LDAPSortKey **)sortKeyList);
  869. #else
  870. ldap_free_sort_keylist(sortKeyList);
  871. #endif
  872. }
  873. int
  874. internal_ldap_create_sort_keylist(LDAPsortkey ***sortKeyList, const char *string_rep)
  875. {
  876. #if defined(USE_OPENLDAP)
  877. return ldap_create_sort_keylist((LDAPSortKey ***)sortKeyList, (char *)string_rep);
  878. #else
  879. return ldap_create_sort_keylist(sortKeyList, string_rep);
  880. #endif
  881. }