vlv.c 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054
  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.c */
  42. /*
  43. * References to on-line documentation here.
  44. *
  45. * http://BLUES/users/dboreham/publish/Design_Documentation/RFCs/draft-ietf-asid-ldapv3-virtuallistview-01.html
  46. * http://warp.mcom.com/server/directory-server/clientsdk/hammerhead/design/virtuallistview.html
  47. * ftp://ftp.ietf.org/internet-drafts/draft-ietf-ldapext-ldapv3-vlv-00.txt
  48. * http://rocknroll/users/merrells/publish/vlvimplementation.html
  49. */
  50. #include "back-ldbm.h"
  51. #include "vlv_srch.h"
  52. #include "vlv_key.h"
  53. static PRUint32 vlv_trim_candidates_byindex(PRUint32 length, const struct vlv_request *vlv_request_control);
  54. static PRUint32 vlv_trim_candidates_byvalue(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control);
  55. static int vlv_build_candidate_list( backend *be, struct vlvIndex* p, const struct vlv_request *vlv_request_control, IDList** candidates, struct vlv_response *vlv_response_control, int is_srchlist_locked);
  56. /* New mutex for vlv locking
  57. PRRWLock * vlvSearchList_lock=NULL;
  58. static struct vlvSearch *vlvSearchList= NULL;
  59. */
  60. #define ISLEGACY(be) (be?(be->be_instance_info?(((ldbm_instance *)be->be_instance_info)->inst_li?(((ldbm_instance *)be->be_instance_info)->inst_li->li_legacy_errcode):0):0):0)
  61. /* Callback to add a new VLV Search specification. Added write lock.*/
  62. int vlv_AddSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  63. {
  64. ldbm_instance *inst = (ldbm_instance *)arg;
  65. struct vlvSearch* newVlvSearch= vlvSearch_new();
  66. backend *be = inst->inst_be;
  67. if (NULL == be) { /* backend is not associated */
  68. return SLAPI_DSE_CALLBACK_ERROR;
  69. }
  70. vlvSearch_init(newVlvSearch, pb, entryBefore, inst);
  71. /* vlvSearchList is modified; need Wlock */
  72. PR_RWLock_Wlock(be->vlvSearchList_lock);
  73. vlvSearch_addtolist(newVlvSearch, (struct vlvSearch **)&be->vlvSearchList);
  74. PR_RWLock_Unlock(be->vlvSearchList_lock);
  75. return SLAPI_DSE_CALLBACK_OK;
  76. }
  77. /* Callback to add a new VLV Index specification. Added write lock.*/
  78. int vlv_AddIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  79. {
  80. struct vlvSearch *parent;
  81. backend *be= ((ldbm_instance*)arg)->inst_be;
  82. Slapi_DN parentdn;
  83. slapi_sdn_init(&parentdn);
  84. slapi_sdn_get_parent(slapi_entry_get_sdn(entryBefore),&parentdn);
  85. {
  86. /* vlvIndex list is modified; need Wlock */
  87. PR_RWLock_Wlock(be->vlvSearchList_lock);
  88. parent= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, &parentdn);
  89. if(parent!=NULL)
  90. {
  91. struct vlvIndex* newVlvIndex= vlvIndex_new();
  92. newVlvIndex->vlv_be=be;
  93. vlvIndex_init(newVlvIndex, be, parent, entryBefore);
  94. vlvSearch_addIndex(parent, newVlvIndex);
  95. }
  96. PR_RWLock_Unlock(be->vlvSearchList_lock);
  97. }
  98. slapi_sdn_done(&parentdn);
  99. return SLAPI_DSE_CALLBACK_OK;
  100. }
  101. /* Callback to delete a VLV Index specification. Added write lock.*/
  102. int vlv_DeleteSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  103. {
  104. struct vlvSearch* p=NULL;
  105. ldbm_instance *inst = (ldbm_instance*)arg;
  106. backend *be= inst->inst_be;
  107. if (instance_set_busy(inst) != 0)
  108. {
  109. LDAPDebug( LDAP_DEBUG_ANY,
  110. "Backend instance: '%s' is already in the middle of "
  111. "another task and cannot be disturbed.\n",
  112. inst->inst_name, 0, 0);
  113. return SLAPI_DSE_CALLBACK_ERROR;
  114. }
  115. /* vlvSearchList is modified; need Wlock */
  116. PR_RWLock_Wlock(be->vlvSearchList_lock);
  117. p = vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, slapi_entry_get_sdn(entryBefore));
  118. if(p!=NULL)
  119. {
  120. LDAPDebug( LDAP_DEBUG_ANY, "Deleted Virtual List View Search (%s).\n", p->vlv_name, 0, 0);
  121. vlvSearch_removefromlist((struct vlvSearch **)&be->vlvSearchList,p->vlv_dn);
  122. vlvSearch_delete(&p);
  123. }
  124. PR_RWLock_Unlock(be->vlvSearchList_lock);
  125. instance_set_not_busy(inst);
  126. return SLAPI_DSE_CALLBACK_OK;
  127. }
  128. /* Stub Callback to delete a VLV Index specification.*/
  129. int vlv_DeleteIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  130. {
  131. ldbm_instance *inst = (ldbm_instance*)arg;
  132. if (inst && (inst->inst_flags & INST_FLAG_BUSY)) {
  133. LDAPDebug( LDAP_DEBUG_ANY,
  134. "Backend instance: '%s' is already in the middle of "
  135. "another task and cannot be disturbed.\n",
  136. inst->inst_name, 0, 0);
  137. return SLAPI_DSE_CALLBACK_ERROR;
  138. } else {
  139. LDAPDebug( LDAP_DEBUG_ANY,
  140. "Deleted Virtual List View Index.\n", 0, 0, 0);
  141. return SLAPI_DSE_CALLBACK_OK;
  142. }
  143. }
  144. /* Callback to modify a VLV Search specification. Added read lock.*/
  145. int vlv_ModifySearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  146. {
  147. struct vlvSearch* p=NULL;
  148. backend *be= ((ldbm_instance*)arg)->inst_be;
  149. PR_RWLock_Rlock(be->vlvSearchList_lock);
  150. p= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, slapi_entry_get_sdn(entryBefore));
  151. if(p!=NULL)
  152. {
  153. LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Search (%s), which will be enabled when the database is rebuilt.\n", p->vlv_name, 0, 0);
  154. }
  155. PR_RWLock_Unlock(be->vlvSearchList_lock);
  156. return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
  157. }
  158. /* Stub callback to modify a VLV Index specification. */
  159. int vlv_ModifyIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  160. {
  161. LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Index.\n", 0, 0, 0);
  162. return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
  163. }
  164. /* Callback to rename a VLV Search specification. Added read lock.*/
  165. int vlv_ModifyRDNSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  166. {
  167. struct vlvSearch* p=NULL;
  168. backend *be= ((ldbm_instance*)arg)->inst_be;
  169. PR_RWLock_Rlock(be->vlvSearchList_lock);
  170. p= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, slapi_entry_get_sdn(entryBefore));
  171. if(p!=NULL)
  172. {
  173. LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Search (%s), which will be enabled when the database is rebuilt.\n", p->vlv_name, 0, 0);
  174. }
  175. PR_RWLock_Unlock(be->vlvSearchList_lock);
  176. return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
  177. }
  178. /* Stub callback to modify a VLV Index specification. */
  179. int vlv_ModifyRDNIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  180. {
  181. LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Index.\n", 0, 0, 0);
  182. return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
  183. }
  184. /* Something may have just read a VLV Entry. */
  185. int vlv_SearchIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  186. {
  187. char *name= slapi_entry_attr_get_charptr(entryBefore,type_vlvName);
  188. backend *be= ((ldbm_instance*)arg)->inst_be;
  189. if (name!=NULL)
  190. {
  191. struct vlvIndex* p= vlv_find_searchname(name, be); /* lock list */
  192. slapi_ch_free((void **) &name);
  193. if(p!=NULL)
  194. {
  195. if(vlvIndex_enabled(p))
  196. {
  197. slapi_entry_attr_set_charptr(entryBefore, type_vlvEnabled, "1");
  198. }
  199. else
  200. {
  201. slapi_entry_attr_set_charptr(entryBefore, type_vlvEnabled, "0");
  202. }
  203. slapi_entry_attr_set_ulong(entryBefore, type_vlvUses, p->vlv_uses);
  204. }
  205. }
  206. return SLAPI_DSE_CALLBACK_OK;
  207. }
  208. /* Handle results of a search for objectclass "vlvIndex". Called by vlv_init at inittime -- no need to lock*/
  209. static int
  210. vlv_init_index_entry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  211. {
  212. struct vlvIndex* newVlvIndex;
  213. struct vlvSearch* pSearch;
  214. Slapi_Backend *be= ((ldbm_instance*)arg)->inst_be;
  215. char ebuf[BUFSIZ];
  216. if(be!=NULL)
  217. {
  218. Slapi_DN parentdn;
  219. slapi_sdn_init(&parentdn);
  220. newVlvIndex= vlvIndex_new();
  221. slapi_sdn_get_parent(slapi_entry_get_sdn(entryBefore),&parentdn);
  222. pSearch= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, &parentdn);
  223. if (pSearch == NULL) {
  224. LDAPDebug( LDAP_DEBUG_ANY, "Parent doesn't exist for entry %s.\n",
  225. escape_string(slapi_entry_get_dn(entryBefore), ebuf), 0, 0);
  226. }
  227. else {
  228. vlvIndex_init(newVlvIndex, be, pSearch, entryBefore);
  229. vlvSearch_addIndex(pSearch, newVlvIndex);
  230. }
  231. slapi_sdn_done(&parentdn);
  232. }
  233. return SLAPI_DSE_CALLBACK_OK;
  234. }
  235. /* Handle results of a search for objectclass "vlvSearch". Called by vlv_init at inittime -- no need to lock*/
  236. static int
  237. vlv_init_search_entry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
  238. {
  239. struct vlvSearch* newVlvSearch= vlvSearch_new();
  240. ldbm_instance *inst = (ldbm_instance*)arg;
  241. backend *be= inst->inst_be;
  242. if (NULL == be) { /* backend is not associated */
  243. return SLAPI_DSE_CALLBACK_ERROR;
  244. }
  245. vlvSearch_init(newVlvSearch, pb, entryBefore, inst);
  246. vlvSearch_addtolist(newVlvSearch, (struct vlvSearch **)&be->vlvSearchList);
  247. return SLAPI_DSE_CALLBACK_OK;
  248. }
  249. /* Look at a new entry, and the set of VLV searches, and see whether
  250. there are any which have deferred initialization and which can now
  251. be initialized given the new entry. Added write lock. */
  252. void vlv_grok_new_import_entry(const struct backentry *e, backend *be)
  253. {
  254. struct vlvSearch* p = NULL;
  255. static int seen_them_all = 0;
  256. int any_not_done = 0;
  257. PR_RWLock_Wlock(be->vlvSearchList_lock);
  258. if (seen_them_all) {
  259. PR_RWLock_Unlock(be->vlvSearchList_lock);
  260. return;
  261. }
  262. p=(struct vlvSearch *)be->vlvSearchList;
  263. /* Walk the list of searches */
  264. for(;p!=NULL;p= p->vlv_next)
  265. /* is this one not initialized ? */
  266. if (0 == p->vlv_initialized) {
  267. any_not_done = 1;
  268. /* Is its base the entry we have here ? */
  269. if (0 == slapi_sdn_compare(backentry_get_sdn(e),p->vlv_base) ) {
  270. /* Then initialize it */
  271. vlvSearch_reinit(p,e);
  272. }
  273. }
  274. if (!any_not_done) {
  275. seen_them_all = 1;
  276. }
  277. PR_RWLock_Unlock(be->vlvSearchList_lock);
  278. }
  279. /*
  280. * Search for the VLV entries which describe the pre-computed indexes we
  281. * support. Register administartion DSE callback functions.
  282. * This is exported to the backend initialisation routine.
  283. * 'inst' may be NULL for non-slapd initialization...
  284. */
  285. int
  286. vlv_init(ldbm_instance *inst)
  287. {
  288. /* The FE DSE *must* be initialised before we get here */
  289. int return_value= LDAP_SUCCESS;
  290. int scope= LDAP_SCOPE_SUBTREE;
  291. char *basedn, buf[512];
  292. const char *searchfilter = "(objectclass=vlvsearch)";
  293. const char *indexfilter = "(objectclass=vlvindex)";
  294. backend *be= inst->inst_be;
  295. /* Initialize lock first time through */
  296. if(be->vlvSearchList_lock == NULL) {
  297. char *rwlockname = slapi_ch_smprintf("vlvSearchList_%s", inst->inst_name);
  298. be->vlvSearchList_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, rwlockname);
  299. slapi_ch_free((void**)&rwlockname);
  300. }
  301. if (NULL != (struct vlvSearch *)be->vlvSearchList)
  302. {
  303. struct vlvSearch *t = NULL;
  304. struct vlvSearch *nt = NULL;
  305. /* vlvSearchList is modified; need Wlock */
  306. PR_RWLock_Wlock(be->vlvSearchList_lock);
  307. for (t = (struct vlvSearch *)be->vlvSearchList; NULL != t; )
  308. {
  309. nt = t->vlv_next;
  310. vlvSearch_delete(&t);
  311. t = nt;
  312. }
  313. be->vlvSearchList = NULL;
  314. PR_RWLock_Unlock(be->vlvSearchList_lock);
  315. }
  316. if (inst == NULL) {
  317. basedn = NULL;
  318. } else {
  319. PR_snprintf(buf, sizeof(buf), "cn=%s,cn=%s,cn=plugins,cn=config",
  320. inst->inst_name, inst->inst_li->li_plugin->plg_name);
  321. basedn = buf;
  322. }
  323. /* Find the VLV Search Entries */
  324. {
  325. Slapi_PBlock *tmp_pb;
  326. slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_init_search_entry,(void *)inst);
  327. tmp_pb= slapi_search_internal(basedn, scope, searchfilter, NULL, NULL, 0);
  328. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_init_search_entry);
  329. slapi_free_search_results_internal(tmp_pb);
  330. slapi_pblock_destroy(tmp_pb);
  331. }
  332. /* Find the VLV Index Entries */
  333. {
  334. Slapi_PBlock *tmp_pb;
  335. slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_init_index_entry,(void*)inst);
  336. tmp_pb= slapi_search_internal(basedn, scope, indexfilter, NULL, NULL, 0);
  337. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_init_index_entry);
  338. slapi_free_search_results_internal(tmp_pb);
  339. slapi_pblock_destroy(tmp_pb);
  340. }
  341. /* Only need to register these callbacks for SLAPD mode... */
  342. if(basedn!=NULL)
  343. {
  344. slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_SearchIndexEntry,(void*)inst);
  345. slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_AddSearchEntry,(void*)inst);
  346. slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_AddIndexEntry,(void*)inst);
  347. slapi_config_register_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifySearchEntry,(void*)inst);
  348. slapi_config_register_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyIndexEntry,(void*)inst);
  349. slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_DeleteSearchEntry,(void*)inst);
  350. slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry,(void*)inst);
  351. slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry,(void*)inst);
  352. slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry,(void*)inst);
  353. }
  354. return return_value;
  355. }
  356. /* Removes callbacks from above when instance is removed. */
  357. int
  358. vlv_remove_callbacks(ldbm_instance *inst) {
  359. int return_value= LDAP_SUCCESS;
  360. int scope= LDAP_SCOPE_SUBTREE;
  361. char *basedn, buf[512];
  362. const char *searchfilter = "(objectclass=vlvsearch)";
  363. const char *indexfilter = "(objectclass=vlvindex)";
  364. if (inst == NULL) {
  365. basedn = NULL;
  366. } else {
  367. PR_snprintf(buf, sizeof(buf), "cn=%s,cn=%s,cn=plugins,cn=config",
  368. inst->inst_name, inst->inst_li->li_plugin->plg_name);
  369. basedn = buf;
  370. }
  371. if(basedn!=NULL)
  372. {
  373. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_SearchIndexEntry);
  374. slapi_config_remove_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_AddSearchEntry);
  375. slapi_config_remove_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_AddIndexEntry);
  376. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifySearchEntry);
  377. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyIndexEntry);
  378. slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_DeleteSearchEntry);
  379. slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry);
  380. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry);
  381. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry);
  382. }
  383. return return_value;
  384. }
  385. /* Find an enabled index which matches this description. */
  386. static struct vlvIndex*
  387. vlv_find_search(backend *be, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control)
  388. {
  389. return vlvSearch_findenabled(be,(struct vlvSearch *)be->vlvSearchList,base,scope,filter,sort_control);
  390. }
  391. /* Find a search which matches this name. Added read lock. */
  392. struct vlvIndex*
  393. vlv_find_searchname(const char * name, backend *be)
  394. {
  395. struct vlvIndex *p=NULL;
  396. PR_RWLock_Rlock(be->vlvSearchList_lock);
  397. p=vlvSearch_findname((struct vlvSearch *)be->vlvSearchList,name);
  398. PR_RWLock_Unlock(be->vlvSearchList_lock);
  399. return p;
  400. }
  401. /* Find a search which matches this indexname. Added to read lock */
  402. struct vlvIndex*
  403. vlv_find_indexname(const char * name, backend *be)
  404. {
  405. struct vlvIndex *p=NULL;
  406. PR_RWLock_Rlock(be->vlvSearchList_lock);
  407. p=vlvSearch_findindexname((struct vlvSearch *)be->vlvSearchList,name);
  408. PR_RWLock_Unlock(be->vlvSearchList_lock);
  409. return p;
  410. }
  411. /* Get a list of known VLV Indexes. Added read lock */
  412. char *
  413. vlv_getindexnames(backend *be)
  414. {
  415. char *n=NULL;
  416. PR_RWLock_Rlock(be->vlvSearchList_lock);
  417. n=vlvSearch_getnames((struct vlvSearch *)be->vlvSearchList);
  418. PR_RWLock_Unlock(be->vlvSearchList_lock);
  419. return n;
  420. }
  421. /* Return the list of VLV indices to the import code. Added read lock */
  422. void
  423. vlv_getindices(IFP callback_fn,void *param, backend *be)
  424. {
  425. /* Traverse the list, calling the import code's callback function */
  426. struct vlvSearch* ps = NULL;
  427. PR_RWLock_Rlock(be->vlvSearchList_lock);
  428. ps = (struct vlvSearch *)be->vlvSearchList;
  429. for(;ps!=NULL;ps= ps->vlv_next)
  430. {
  431. struct vlvIndex* pi= ps->vlv_index;
  432. for(;pi!=NULL;pi= pi->vlv_next)
  433. {
  434. callback_fn(pi->vlv_attrinfo,param);
  435. }
  436. }
  437. PR_RWLock_Unlock(be->vlvSearchList_lock);
  438. }
  439. /*
  440. * Create a key for the entry in the vlv index.
  441. *
  442. * The key is a composite of a value from each sorted attribute.
  443. *
  444. * If a sorted attribute has many values, then the key is built
  445. * with the attribute value with the lowest value.
  446. *
  447. * The primary sorted attribute value is followed by a 0x00 to
  448. * ensure that short attribute values appear before longer ones.
  449. *
  450. * Many entries may have the same attribute values, which would
  451. * generate the same composite key, so we append the EntryID
  452. * to ensure the uniqueness of the key.
  453. *
  454. * Always creates a key. Never returns NULL.
  455. */
  456. static struct vlv_key *
  457. vlv_create_key(struct vlvIndex* p, struct backentry* e)
  458. {
  459. struct berval val;
  460. unsigned char char_min = 0x00;
  461. unsigned char char_max = 0xFF;
  462. struct vlv_key *key= vlv_key_new();
  463. if(p->vlv_sortkey!=NULL)
  464. {
  465. /* Foreach sorted attribute... */
  466. int sortattr= 0;
  467. while(p->vlv_sortkey[sortattr]!=NULL)
  468. {
  469. Slapi_Attr* attr= attrlist_find(e->ep_entry->e_attrs, p->vlv_sortkey[sortattr]->sk_attrtype);
  470. {
  471. /*
  472. * If there's a matching rule associated with the sorted
  473. * attribute then use the indexer to mangle the attr values.
  474. * This ensures that the international characters will
  475. * collate in the correct order.
  476. */
  477. /* xxxPINAKI */
  478. /* need to free some stuff! */
  479. Slapi_Value **cvalue = NULL;
  480. struct berval **value = NULL, *lowest_value = NULL;
  481. int free_value= 0;
  482. if (attr != NULL && !valueset_isempty(&attr->a_present_values))
  483. {
  484. /* Sorted attribute found. */
  485. int totalattrs;
  486. if (p->vlv_sortkey[sortattr]->sk_matchruleoid==NULL)
  487. {
  488. /* No matching rule. Syntax Plugin mangles value. */
  489. Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
  490. slapi_call_syntax_values2keys_sv( p->vlv_syntax_plugin[sortattr], va, &cvalue, LDAP_FILTER_EQUALITY );
  491. valuearray_get_bervalarray(cvalue,&value);
  492. /* XXXSD need to free some more stuff */
  493. {
  494. int numval;
  495. for (numval=0; cvalue&&cvalue[numval];numval++) {
  496. slapi_value_free(&cvalue[numval]);
  497. }
  498. if (cvalue)
  499. slapi_ch_free((void **)&cvalue);
  500. }
  501. free_value= 1;
  502. }
  503. else
  504. {
  505. /* Matching rule. Do the magic mangling. Plugin owns the memory. */
  506. if(p->vlv_mrpb[sortattr]!=NULL)
  507. {
  508. /* xxxPINAKI */
  509. struct berval **bval=NULL;
  510. Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
  511. valuearray_get_bervalarray(va,&bval);
  512. matchrule_values_to_keys(p->vlv_mrpb[sortattr],bval,&value);
  513. }
  514. }
  515. for(totalattrs=0;value[totalattrs]!=NULL;totalattrs++) {}; /* Total Number of Attributes */
  516. if(totalattrs==1)
  517. {
  518. lowest_value= value[0];
  519. }
  520. else
  521. {
  522. lowest_value = attr_value_lowest(value, slapi_berval_cmp);
  523. }
  524. } /* end of if (attr != NULL && ...) */
  525. if(p->vlv_sortkey[sortattr]->sk_reverseorder)
  526. {
  527. /*
  528. * This attribute is reverse sorted, so we must
  529. * invert the attribute value so that the keys
  530. * will be in the correct order.
  531. */
  532. unsigned int i;
  533. char *attributeValue = NULL;
  534. /* Bug 605477 : Don't malloc 0 bytes */
  535. if (attr != NULL && lowest_value && lowest_value->bv_len != 0) {
  536. attributeValue = (char*)slapi_ch_malloc(lowest_value->bv_len);
  537. for(i=0;i<lowest_value->bv_len;i++)
  538. {
  539. attributeValue[i]= UCHAR_MAX - ((char*)lowest_value->bv_val)[i];
  540. }
  541. val.bv_len= lowest_value->bv_len;
  542. val.bv_val= (void*)attributeValue;
  543. } else {
  544. /* Reverse Sort: We use an attribute value of 0x00 when
  545. * there is no attribute value or attrbute is absent
  546. */
  547. val.bv_val= (void*)&char_min;
  548. val.bv_len= 1;
  549. }
  550. vlv_key_addattr(key,&val);
  551. slapi_ch_free((void**)&attributeValue);
  552. }
  553. else
  554. {
  555. /*
  556. * This attribute is forward sorted, so add the
  557. * attribute value to the end of all the keys.
  558. */
  559. /* If the forward-sorted attribute is absent or has no
  560. * value, we need to use the value of 0xFF.
  561. */
  562. if (attr != NULL && lowest_value && lowest_value->bv_len > 0) {
  563. vlv_key_addattr(key,lowest_value);
  564. } else {
  565. val.bv_val = (void*)&char_max;
  566. val.bv_len = 1;
  567. vlv_key_addattr(key,&val);
  568. }
  569. }
  570. if(sortattr==0)
  571. {
  572. /*
  573. * If this is the first attribute (the typedown attribute)
  574. * then it should be followed by a zero. This is to ensure
  575. * that shorter attribute values appear before longer ones.
  576. */
  577. char zero = 0;
  578. val.bv_len= 1;
  579. val.bv_val= (void*)&zero;
  580. vlv_key_addattr(key,&val);
  581. }
  582. if(free_value)
  583. {
  584. ber_bvecfree(value);
  585. }
  586. }
  587. sortattr++;
  588. }
  589. }
  590. {
  591. /* Append the EntryID to the key to ensure uniqueness */
  592. val.bv_len= sizeof(e->ep_id);
  593. val.bv_val= (void*)&e->ep_id;
  594. vlv_key_addattr(key,&val);
  595. }
  596. return key;
  597. }
  598. /*
  599. * Insert or Delete the entry to or from the index
  600. */
  601. static int
  602. do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct vlvIndex* pIndex, struct backentry* entry, int insert)
  603. {
  604. backend *be;
  605. int rc= 0;
  606. DB *db = NULL;
  607. DB_TXN *db_txn = NULL;
  608. struct vlv_key *key = NULL;
  609. slapi_pblock_get(pb, SLAPI_BACKEND, &be);
  610. rc = dblayer_get_index_file(be, pIndex->vlv_attrinfo, &db, DBOPEN_CREATE);
  611. if (rc != 0) {
  612. if(rc != DB_LOCK_DEADLOCK)
  613. LDAPDebug(LDAP_DEBUG_ANY, "VLV: can't get index file '%s' (err %d)\n",
  614. pIndex->vlv_attrinfo->ai_type, rc, 0);
  615. return rc;
  616. }
  617. key = vlv_create_key(pIndex,entry);
  618. if (NULL != txn) {
  619. db_txn = txn->back_txn_txn;
  620. } else {
  621. /* Very bad idea to do this outside of a transaction */
  622. }
  623. if (insert) {
  624. DBT data = {0};
  625. data.size = sizeof(entry->ep_id);
  626. data.data = &entry->ep_id;
  627. rc = db->put(db, db_txn, &key->key, &data, 0);
  628. if (rc == 0) {
  629. LDAPDebug(LDAP_DEBUG_TRACE,
  630. "vlv_update_index: %s Insert %s ID=%lu\n",
  631. pIndex->vlv_name, key->key.data, (u_long)entry->ep_id);
  632. vlvIndex_increment_indexlength(pIndex, db, txn);
  633. } else if (rc == DB_RUNRECOVERY) {
  634. ldbm_nasty(pIndex->vlv_name,77,rc);
  635. } else if(rc != DB_LOCK_DEADLOCK) {
  636. /* jcm: This error is valid if the key already exists.
  637. * Identical multi valued attr values could do this. */
  638. LDAPDebug(LDAP_DEBUG_TRACE,
  639. "vlv_update_index: %s Insert %s ID=%lu FAILED\n",
  640. pIndex->vlv_name, key->key.data, (u_long)entry->ep_id);
  641. }
  642. } else {
  643. LDAPDebug(LDAP_DEBUG_TRACE,
  644. "vlv_update_index: %s Delete %s\n",
  645. pIndex->vlv_name, key->key.data, 0);
  646. rc = db->del(db, db_txn, &key->key, 0);
  647. if (rc == 0) {
  648. vlvIndex_decrement_indexlength(pIndex, db, txn);
  649. } else if (rc == DB_RUNRECOVERY) {
  650. ldbm_nasty(pIndex->vlv_name,78,rc);
  651. } else if (rc != DB_LOCK_DEADLOCK) {
  652. LDAPDebug(LDAP_DEBUG_TRACE,
  653. "vlv_update_index: %s Delete %s FAILED\n",
  654. pIndex->vlv_name, key->key.data, 0);
  655. }
  656. }
  657. vlv_key_delete(&key);
  658. dblayer_release_index_file(be, pIndex->vlv_attrinfo, db);
  659. return rc;
  660. }
  661. /*
  662. * Given an entry modification check if a VLV index needs to be updated.
  663. */
  664. int
  665. vlv_update_index(struct vlvIndex* p, back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct backentry* oldEntry, struct backentry* newEntry)
  666. {
  667. int return_value=0;
  668. /* Check if the old entry is in this VLV index */
  669. if(oldEntry!=NULL)
  670. {
  671. if(slapi_sdn_scope_test(backentry_get_sdn(oldEntry),vlvIndex_getBase(p),vlvIndex_getScope(p)))
  672. {
  673. if(slapi_filter_test( pb, oldEntry->ep_entry, vlvIndex_getFilter(p), 0 /* No ACL Check */) == 0 )
  674. {
  675. /* Remove the entry from the index */
  676. return_value=do_vlv_update_index(txn, li, pb, p, oldEntry, 0 /* Delete Key */);
  677. }
  678. }
  679. }
  680. /* Check if the new entry should be in the VLV index */
  681. if(newEntry!=NULL)
  682. {
  683. if(slapi_sdn_scope_test(backentry_get_sdn(newEntry),vlvIndex_getBase(p),vlvIndex_getScope(p)))
  684. {
  685. if(slapi_filter_test( pb, newEntry->ep_entry, vlvIndex_getFilter(p), 0 /* No ACL Check */) == 0 )
  686. {
  687. /* Add the entry to the index */
  688. return_value=do_vlv_update_index(txn, li, pb, p, newEntry, 1 /* Insert Key */);
  689. }
  690. }
  691. }
  692. return return_value;
  693. }
  694. /*
  695. * Given an entry modification check if a VLV index needs to be updated.
  696. *
  697. * This is called for every modifying operation, so it must be very efficient.
  698. *
  699. * We need to know if we're adding, deleting, or modifying
  700. * because we could be leaving and/or joining an index
  701. *
  702. * ADD: oldEntry==NULL && newEntry!=NULL
  703. * DEL: oldEntry!=NULL && newEntry==NULL
  704. * MOD: oldEntry!=NULL && newEntry!=NULL
  705. *
  706. * JCM: If only non-sorted attributes are changed, then the indexes don't need updating.
  707. * JCM: Detecting this fact, given multi-valued atribibutes, might be tricky...
  708. * Read lock (traverse vlvSearchList; no change on vlvSearchList/vlvIndex lists)
  709. */
  710. int
  711. vlv_update_all_indexes(back_txn *txn, backend *be, Slapi_PBlock *pb, struct backentry* oldEntry, struct backentry* newEntry)
  712. {
  713. int return_value= LDAP_SUCCESS;
  714. struct vlvSearch* ps=NULL;
  715. struct ldbminfo *li = ((ldbm_instance *)be->be_instance_info)->inst_li;
  716. PR_RWLock_Rlock(be->vlvSearchList_lock);
  717. ps = (struct vlvSearch *)be->vlvSearchList;
  718. for(;ps!=NULL;ps= ps->vlv_next)
  719. {
  720. struct vlvIndex* pi= ps->vlv_index;
  721. for (return_value = LDAP_SUCCESS; return_value == LDAP_SUCCESS && pi!=NULL; pi=pi->vlv_next)
  722. return_value=vlv_update_index(pi, txn, li, pb, oldEntry, newEntry);
  723. }
  724. PR_RWLock_Unlock(be->vlvSearchList_lock);
  725. return return_value;
  726. }
  727. /*
  728. * Determine the range of record numbers to return.
  729. * Prevent an underrun, or overrun.
  730. */
  731. /* jcm: Should we make sure that start < stop */
  732. static void
  733. determine_result_range(const struct vlv_request *vlv_request_control, PRUint32 index, PRUint32 length, PRUint32* pstart, PRUint32 *pstop)
  734. {
  735. if (vlv_request_control == NULL)
  736. {
  737. *pstart= 0;
  738. if (0 == length) /* 609377: index size could be 0 */
  739. {
  740. *pstop= 0;
  741. }
  742. else
  743. {
  744. *pstop= length - 1;
  745. }
  746. }
  747. else
  748. {
  749. /* Make sure we don't run off the start */
  750. if(index < vlv_request_control->beforeCount)
  751. {
  752. *pstart= 0;
  753. }
  754. else
  755. {
  756. *pstart= index - vlv_request_control->beforeCount;
  757. }
  758. /* Make sure we don't run off the end */
  759. if(UINT_MAX - index > vlv_request_control->afterCount)
  760. {
  761. *pstop= index + vlv_request_control->afterCount;
  762. }
  763. else
  764. {
  765. *pstop= UINT_MAX;
  766. }
  767. /* Client tried to index off the end */
  768. if (0 == length) /* 609377: index size could be 0 */
  769. {
  770. *pstop= 0;
  771. }
  772. else if(*pstop > length - 1)
  773. {
  774. *pstop= length - 1;
  775. }
  776. }
  777. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_determine_result_range: Result Range %lu-%lu\n", *pstart, *pstop, 0 );
  778. }
  779. /*
  780. * This is a utility function to pass the client
  781. * supplied attribute value through the appropriate
  782. * matching rule indexer.
  783. *
  784. * It allocates a berval vector which the caller
  785. * must free.
  786. */
  787. static struct berval **
  788. vlv_create_matching_rule_value( Slapi_PBlock* pb, struct berval *original_value)
  789. {
  790. struct berval **value= NULL;
  791. if(pb!=NULL)
  792. {
  793. struct berval **outvalue = NULL;
  794. struct berval *invalue[2];
  795. invalue[0]= original_value; /* jcm: cast away const */
  796. invalue[1]= NULL;
  797. /* The plugin owns the memory it returns in outvalue */
  798. matchrule_values_to_keys(pb,invalue,&outvalue);
  799. if(outvalue!=NULL)
  800. {
  801. value= slapi_ch_bvecdup(outvalue);
  802. }
  803. }
  804. if(value==NULL)
  805. {
  806. struct berval *outvalue[2];
  807. outvalue[0]= original_value; /* jcm: cast away const */
  808. outvalue[1]= NULL;
  809. value= slapi_ch_bvecdup(outvalue);
  810. }
  811. return value;
  812. }
  813. /*
  814. * Find the record number in a VLV index for a given attribute value.
  815. * The returned index is counted from zero.
  816. */
  817. static PRUint32
  818. vlv_build_candidate_list_byvalue( struct vlvIndex* p, DBC *dbc, PRUint32 length, const struct vlv_request *vlv_request_control)
  819. {
  820. PRUint32 si= 0; /* The Selected Index */
  821. int err= 0;
  822. DBT key= {0};
  823. DBT data= {0};
  824. /*
  825. * If the primary sorted attribute has an associated
  826. * matching rule, then we must mangle the typedown
  827. * value.
  828. */
  829. struct berval **typedown_value= NULL;
  830. struct berval *invalue[2];
  831. invalue[0]= (struct berval *)&vlv_request_control->value; /* jcm: cast away const */
  832. invalue[1]= NULL;
  833. if (p->vlv_sortkey[0]->sk_matchruleoid==NULL)
  834. {
  835. slapi_call_syntax_values2keys(p->vlv_syntax_plugin[0],invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
  836. }
  837. else
  838. {
  839. typedown_value= vlv_create_matching_rule_value(p->vlv_mrpb[0],(struct berval *)&vlv_request_control->value); /* jcm: cast away const */
  840. }
  841. if(p->vlv_sortkey[0]->sk_reverseorder)
  842. {
  843. /*
  844. * The primary attribute is reverse sorted, so we must
  845. * invert the typedown value in order to match the key.
  846. */
  847. unsigned int i;
  848. for(i=0;i<(*typedown_value)->bv_len;i++)
  849. {
  850. ((char*)(*typedown_value)->bv_val)[i]= UCHAR_MAX - ((char*)(*typedown_value)->bv_val)[i];
  851. }
  852. }
  853. key.flags= DB_DBT_MALLOC;
  854. key.size= typedown_value[0]->bv_len;
  855. key.data= typedown_value[0]->bv_val;
  856. data.flags= DB_DBT_MALLOC;
  857. err= dbc->c_get(dbc,&key,&data,DB_SET_RANGE);
  858. if(err==0)
  859. {
  860. slapi_ch_free(&(data.data));
  861. err= dbc->c_get(dbc,&key,&data,DB_GET_RECNO);
  862. if(err==0)
  863. {
  864. si= *((db_recno_t*)data.data);
  865. /* Records are numbered from one. */
  866. si--;
  867. slapi_ch_free(&(data.data));
  868. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_build_candidate_list_byvalue: Found. Index=%lu\n",si,0,0);
  869. }
  870. else
  871. {
  872. /* Couldn't get the record number for the record we found. */
  873. }
  874. }
  875. else
  876. {
  877. /* Couldn't find an entry which matches the value,
  878. * so return the last entry
  879. * (609377) when the index file is empty, there is no "last entry".
  880. */
  881. if (0 == length)
  882. {
  883. si = 0;
  884. }
  885. else
  886. {
  887. si = length - 1;
  888. }
  889. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_build_candidate_list_byvalue: Not Found. Index=%lu\n",si,0,0);
  890. }
  891. if (key.data != typedown_value[0]->bv_val) { /* in case new key is set
  892. in dbc->c_get(DB_SET_RANGE) */
  893. slapi_ch_free(&(key.data));
  894. }
  895. ber_bvecfree((struct berval**)typedown_value);
  896. return si;
  897. }
  898. static int
  899. vlv_idl_sort_cmp(const void *x, const void *y)
  900. {
  901. return *(ID *)x - *(ID *)y;
  902. }
  903. /* build a candidate list (IDL) from a VLV index, given the starting index
  904. * and the ending index (as an inclusive list).
  905. * returns 0 on success, or an LDAP error code.
  906. */
  907. int vlv_build_idl(PRUint32 start, PRUint32 stop, DB *db, DBC *dbc,
  908. IDList **candidates, int dosort)
  909. {
  910. IDList *idl = NULL;
  911. int err;
  912. PRUint32 recno;
  913. DBT key = {0};
  914. DBT data = {0};
  915. ID id;
  916. idl = idl_alloc(stop-start+1);
  917. if (!idl) {
  918. /* out of memory :( */
  919. return LDAP_OPERATIONS_ERROR;
  920. }
  921. recno = start+1;
  922. key.size = sizeof(recno);
  923. key.data = &recno;
  924. key.flags = DB_DBT_MALLOC;
  925. data.ulen = sizeof(ID);
  926. data.data = &id;
  927. data.flags = DB_DBT_USERMEM; /* don't alloc */
  928. err = dbc->c_get(dbc, &key, &data, DB_SET_RECNO);
  929. while ((err == 0) && (recno <= stop+1)) {
  930. if (key.data != &recno)
  931. slapi_ch_free(&(key.data));
  932. idl_append(idl, *(ID *)data.data);
  933. if (++recno <= stop+1) {
  934. err = dbc->c_get(dbc, &key, &data, DB_NEXT);
  935. }
  936. }
  937. if (err != 0) {
  938. /* some db error...? */
  939. LDAPDebug(LDAP_DEBUG_ANY, "vlv_build_idl: can't follow db cursor "
  940. "(err %d)\n", err, 0, 0);
  941. if (err == ENOMEM)
  942. LDAPDebug(LDAP_DEBUG_ANY, " nomem: wants %d key, %d data\n",
  943. key.size, data.size, 0);
  944. return LDAP_OPERATIONS_ERROR;
  945. }
  946. /* success! */
  947. if (idl) {
  948. if (candidates)
  949. {
  950. if (dosort)
  951. {
  952. qsort((void *)&idl->b_ids[0], idl->b_nids,
  953. (size_t)sizeof(ID), vlv_idl_sort_cmp);
  954. }
  955. *candidates = idl;
  956. }
  957. else
  958. idl_free(idl); /* ??? */
  959. }
  960. return LDAP_SUCCESS;
  961. }
  962. /* This function does vlv_access, searching and building list all while holding read lock
  963. 1. vlv_find_search fails, set:
  964. unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
  965. slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
  966. return FIND_SEARCH FAILED
  967. 2. vlvIndex_accessallowed fails
  968. return VLV_LDBM_ACCESS_DENIED
  969. 3. vlv_build_candidate_list fails:
  970. return VLV_BLD_LIST_FAILED
  971. 4. return LDAP_SUCCESS
  972. */
  973. int
  974. vlv_search_build_candidate_list(Slapi_PBlock *pb, const Slapi_DN *base, int *vlv_rc, const sort_spec* sort_control,
  975. const struct vlv_request *vlv_request_control,
  976. IDList** candidates, struct vlv_response *vlv_response_control) {
  977. struct vlvIndex* pi = NULL;
  978. backend *be;
  979. int scope, rc=LDAP_SUCCESS;
  980. char *fstr;
  981. slapi_pblock_get( pb, SLAPI_BACKEND, &be );
  982. slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
  983. slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &fstr );
  984. PR_RWLock_Rlock(be->vlvSearchList_lock);
  985. if((pi=vlv_find_search(be, base, scope, fstr, sort_control)) == NULL) {
  986. unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
  987. PR_RWLock_Unlock(be->vlvSearchList_lock);
  988. slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
  989. rc = VLV_FIND_SEARCH_FAILED;
  990. } else if((*vlv_rc=vlvIndex_accessallowed(pi, pb)) != LDAP_SUCCESS) {
  991. PR_RWLock_Unlock(be->vlvSearchList_lock);
  992. rc = VLV_ACCESS_DENIED;
  993. } else if ((*vlv_rc=vlv_build_candidate_list(be,pi,vlv_request_control,candidates,vlv_response_control, 1)) != LDAP_SUCCESS) {
  994. rc = VLV_BLD_LIST_FAILED;
  995. vlv_response_control->result=*vlv_rc;
  996. }
  997. return rc;
  998. }
  999. /*
  1000. * Given the SORT and VLV controls return a candidate list from the
  1001. * pre-computed index file.
  1002. *
  1003. * Returns:
  1004. * success (0),
  1005. * operationsError (1),
  1006. * unwillingToPerform (53),
  1007. * timeLimitExceeded (3),
  1008. * adminLimitExceeded (11),
  1009. * indexRangeError (61),
  1010. * other (80)
  1011. */
  1012. static int
  1013. vlv_build_candidate_list( backend *be, struct vlvIndex* p, const struct vlv_request *vlv_request_control, IDList** candidates, struct vlv_response *vlv_response_control, int is_srchlist_locked)
  1014. {
  1015. int return_value = LDAP_SUCCESS;
  1016. DB *db = NULL;
  1017. DBC *dbc = NULL;
  1018. int rc, err;
  1019. PRUint32 si = 0; /* The Selected Index */
  1020. PRUint32 length;
  1021. int do_trim= 1;
  1022. LDAPDebug(LDAP_DEBUG_TRACE,
  1023. "=> vlv_build_candidate_list: %s %s Using VLV Index %s\n",
  1024. slapi_sdn_get_dn(vlvIndex_getBase(p)), p->vlv_search->vlv_filter,
  1025. vlvIndex_getName(p));
  1026. if (!vlvIndex_online(p)) {
  1027. if (is_srchlist_locked) {
  1028. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1029. }
  1030. return -1;
  1031. }
  1032. rc = dblayer_get_index_file(be, p->vlv_attrinfo, &db, 0);
  1033. if (rc != 0) {
  1034. /* shouldn't happen */
  1035. LDAPDebug(LDAP_DEBUG_ANY, "VLV: can't get index file '%s' (err %d)\n",
  1036. p->vlv_attrinfo->ai_type, rc, 0);
  1037. if (is_srchlist_locked) {
  1038. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1039. }
  1040. return -1;
  1041. }
  1042. length = vlvIndex_get_indexlength(p, db, 0 /* txn */);
  1043. /* Increment the usage counter */
  1044. vlvIndex_incrementUsage(p);
  1045. if (is_srchlist_locked) {
  1046. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1047. }
  1048. err = db->cursor(db, 0 /* txn */, &dbc, 0);
  1049. if (err != 0) {
  1050. /* shouldn't happen */
  1051. LDAPDebug(LDAP_DEBUG_ANY, "VLV: couldn't get cursor (err %d)\n",
  1052. rc, 0, 0);
  1053. return -1;
  1054. }
  1055. if (vlv_request_control)
  1056. {
  1057. switch(vlv_request_control->tag) {
  1058. case 0: /* byIndex */
  1059. si = vlv_trim_candidates_byindex(length, vlv_request_control);
  1060. break;
  1061. case 1: /* byValue */
  1062. si = vlv_build_candidate_list_byvalue(p, dbc, length,
  1063. vlv_request_control);
  1064. if (si==length) {
  1065. do_trim = 0;
  1066. /* minimum idl_alloc size should be 1; 0 is considered ALLID */
  1067. *candidates = idl_alloc(1);
  1068. }
  1069. break;
  1070. default:
  1071. /* Some wierd tag value. Shouldn't ever happen */
  1072. if (ISLEGACY(be)) {
  1073. return_value = LDAP_OPERATIONS_ERROR;
  1074. } else {
  1075. return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
  1076. }
  1077. break;
  1078. }
  1079. /* Tell the client what the real content count is.
  1080. * Client counts from 1. */
  1081. vlv_response_control->targetPosition = si + 1;
  1082. vlv_response_control->contentCount = length;
  1083. vlv_response_control->result = return_value;
  1084. }
  1085. if ((return_value == LDAP_SUCCESS) && do_trim) {
  1086. /* Work out the range of records to return */
  1087. PRUint32 start, stop;
  1088. determine_result_range(vlv_request_control, si, length, &start, &stop);
  1089. /* fetch the idl */
  1090. return_value = vlv_build_idl(start, stop, db, dbc, candidates, 0);
  1091. }
  1092. dbc->c_close(dbc);
  1093. dblayer_release_index_file( be, p->vlv_attrinfo, db );
  1094. return return_value;
  1095. }
  1096. /*
  1097. * Given a candidate list and a filter specification, filter the candidate list
  1098. *
  1099. * Returns:
  1100. * success (0),
  1101. * operationsError (1),
  1102. * unwillingToPerform (53),
  1103. * timeLimitExceeded (3),
  1104. * adminLimitExceeded (11),
  1105. * indexRangeError (61),
  1106. * other (80)
  1107. */
  1108. int
  1109. vlv_filter_candidates(backend *be, Slapi_PBlock *pb, const IDList *candidates, const Slapi_DN *base, int scope, Slapi_Filter *filter, IDList** filteredCandidates, int lookthrough_limit, time_t time_up)
  1110. {
  1111. IDList* resultIdl= NULL;
  1112. int return_value = LDAP_SUCCESS;
  1113. /* Refuse to filter a non-existent IDlist */
  1114. if (NULL == candidates)
  1115. {
  1116. return LDAP_UNWILLING_TO_PERFORM;
  1117. }
  1118. LDAPDebug( LDAP_DEBUG_TRACE, "=> vlv_filter_candidates: Filtering %lu Candidates\n",(u_long)candidates->b_nids, 0, 0 );
  1119. if (0 == return_value && candidates->b_nids>0)
  1120. {
  1121. /* jcm: Could be an idlist function. create_filtered_idlist */
  1122. /* Iterate over the ID List applying the filter */
  1123. int lookedat= 0;
  1124. int done= 0;
  1125. int counter= 0;
  1126. ID id = NOID;
  1127. idl_iterator current = idl_iterator_init(candidates);
  1128. resultIdl= idl_alloc(candidates->b_nids);
  1129. do
  1130. {
  1131. id = idl_iterator_dereference_increment(&current, candidates);
  1132. if ( id != NOID )
  1133. {
  1134. int err= 0;
  1135. struct backentry *e= NULL;
  1136. e = id2entry( be, id, NULL, &err );
  1137. if ( e == NULL )
  1138. {
  1139. /*
  1140. * The ALLIDS ID List contains IDs for which there is no entry.
  1141. * This is because the entries have been deleted. An error in
  1142. * this case is ok.
  1143. */
  1144. if(!(ALLIDS(candidates) && err==DB_NOTFOUND))
  1145. {
  1146. LDAPDebug( LDAP_DEBUG_ANY, "vlv_filter_candidates: Candidate %lu not found err=%d\n", (u_long)id, err, 0 );
  1147. }
  1148. }
  1149. else
  1150. {
  1151. lookedat++;
  1152. if(slapi_sdn_scope_test(backentry_get_sdn(e),base,scope))
  1153. {
  1154. if ( slapi_filter_test( pb, e->ep_entry, filter, 0 /* No ACL Check */) == 0 )
  1155. {
  1156. /* The entry passed the filter test, add the id to the list */
  1157. LDAPDebug( LDAP_DEBUG_TRACE, "vlv_filter_candidates: Candidate %lu Passed Filter\n", (u_long)id, 0, 0 );
  1158. idl_append(resultIdl,id);
  1159. }
  1160. }
  1161. cache_return(&(((ldbm_instance *) be->be_instance_info)->inst_cache), &e);
  1162. }
  1163. }
  1164. done= slapi_op_abandoned(pb);
  1165. /* Check to see if our journey is really necessary */
  1166. if ( counter++ % 10 == 0 )
  1167. {
  1168. /* check time limit */
  1169. time_t curtime = current_time();
  1170. if ( time_up != -1 && curtime > time_up )
  1171. {
  1172. return_value= LDAP_TIMELIMIT_EXCEEDED;
  1173. done= 1;
  1174. }
  1175. /* check lookthrough limit */
  1176. if ( lookthrough_limit != -1 && lookedat>lookthrough_limit )
  1177. {
  1178. return_value= LDAP_ADMINLIMIT_EXCEEDED;
  1179. done= 1;
  1180. }
  1181. }
  1182. } while (!done && id!=NOID);
  1183. }
  1184. if(filteredCandidates!=NULL)
  1185. *filteredCandidates= resultIdl;
  1186. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_filter_candidates: Filtering done\n",0, 0, 0 );
  1187. return return_value;
  1188. }
  1189. /*
  1190. * Given a candidate list and a virtual list view specification, trim the candidate list
  1191. *
  1192. * Returns:
  1193. * success (0),
  1194. * operationsError (1),
  1195. * unwillingToPerform (53),
  1196. * timeLimitExceeded (3),
  1197. * adminLimitExceeded (11),
  1198. * indexRangeError (61),
  1199. * other (80)
  1200. */
  1201. int
  1202. vlv_trim_candidates(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control, IDList** trimmedCandidates,struct vlv_response *vlv_response_control)
  1203. {
  1204. IDList* resultIdl= NULL;
  1205. int return_value= LDAP_SUCCESS;
  1206. PRUint32 si= 0; /* The Selected Index */
  1207. int do_trim= 1;
  1208. /* Refuse to trim a non-existent IDlist */
  1209. if (NULL == candidates || candidates->b_nids==0)
  1210. {
  1211. return LDAP_UNWILLING_TO_PERFORM;
  1212. }
  1213. switch(vlv_request_control->tag)
  1214. {
  1215. case 0: /* byIndex */
  1216. si= vlv_trim_candidates_byindex(candidates->b_nids, vlv_request_control);
  1217. break;
  1218. case 1: /* byValue */
  1219. si= vlv_trim_candidates_byvalue(be, candidates, sort_control, vlv_request_control);
  1220. /* Don't bother sending results if the attribute value wasn't found */
  1221. if(si==candidates->b_nids)
  1222. {
  1223. do_trim= 0;
  1224. /* minimum idl_alloc size should be 1; 0 is considered ALLID */
  1225. resultIdl= idl_alloc(1);
  1226. }
  1227. break;
  1228. default:
  1229. /* Some wierd tag value. Shouldn't ever happen */
  1230. if (ISLEGACY(be)) {
  1231. return_value = LDAP_OPERATIONS_ERROR;
  1232. } else {
  1233. return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
  1234. }
  1235. break;
  1236. }
  1237. /* Tell the client what the real content count is. Clients count from 1 */
  1238. vlv_response_control->targetPosition= si + 1;
  1239. vlv_response_control->contentCount= candidates->b_nids;
  1240. if(return_value==LDAP_SUCCESS && do_trim)
  1241. {
  1242. /* Work out the range of records to return */
  1243. PRUint32 start, stop;
  1244. determine_result_range(vlv_request_control,si,candidates->b_nids,&start,&stop);
  1245. /* Build a new list containing the (start..stop) range */
  1246. /* JCM: Should really be a function in idlist.c to copy a range */
  1247. resultIdl= idl_alloc(stop-start+1);
  1248. {
  1249. PRUint32 cursor= 0;
  1250. for(cursor=start;cursor<=stop;cursor++)
  1251. {
  1252. LDAPDebug( LDAP_DEBUG_TRACE, "vlv_trim_candidates: Include ID %lu\n",(u_long)candidates->b_ids[cursor], 0, 0 );
  1253. idl_append(resultIdl,candidates->b_ids[cursor]);
  1254. }
  1255. }
  1256. }
  1257. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates: Trimmed list contains %lu entries.\n",(u_long)resultIdl->b_nids, 0, 0 );
  1258. if(trimmedCandidates!=NULL)
  1259. *trimmedCandidates= resultIdl;
  1260. return return_value;
  1261. }
  1262. /*
  1263. * Work out the Selected Index given the length of the candidate list
  1264. * and the request control from the client.
  1265. *
  1266. * If the client sends Index==0 we behave as if I=1
  1267. * If the client sends Index==Size==1 we behave as if I=1, S=0
  1268. */
  1269. static PRUint32
  1270. vlv_trim_candidates_byindex(PRUint32 length, const struct vlv_request *vlv_request_control)
  1271. {
  1272. PRUint32 si= 0; /* The Selected Index */
  1273. LDAPDebug( LDAP_DEBUG_TRACE, "=> vlv_trim_candidates_byindex: length=%u index=%d size=%d\n",length, vlv_request_control->index, vlv_request_control->contentCount );
  1274. if(vlv_request_control->index==0)
  1275. {
  1276. /* Always select the first entry in the list */
  1277. si= 0;
  1278. }
  1279. else
  1280. {
  1281. if(vlv_request_control->contentCount==0)
  1282. {
  1283. /* The client has no idea what the content count might be. */
  1284. /* Can't scale the index, so use as is */
  1285. si= vlv_request_control->index;
  1286. if (0 == length) /* 609377: index size could be 0 */
  1287. {
  1288. if (si > 0)
  1289. {
  1290. si = length;
  1291. }
  1292. }
  1293. else if(si > length - 1)
  1294. {
  1295. si= length - 1;
  1296. }
  1297. }
  1298. else
  1299. {
  1300. if(vlv_request_control->index>=vlv_request_control->contentCount)
  1301. {
  1302. /* Always select the last entry in the list */
  1303. if (0 == length) /* 609377: index size could be 0 */
  1304. {
  1305. si = 0;
  1306. }
  1307. else
  1308. {
  1309. si= length-1;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. /* The three components of this expression are (PRUint32) and may well have a value up to UINT_MAX */
  1315. /* SelectedIndex = ActualContentCount * ( ClientIndex / ClientContentCount ) */
  1316. si= ((PRUint32)((double)length * (double)(vlv_request_control->index / (double)vlv_request_control->contentCount )));
  1317. }
  1318. }
  1319. }
  1320. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates_byindex: Selected Index %lu\n",si, 0, 0 );
  1321. return si;
  1322. }
  1323. /*
  1324. * Iterate over the Candidate ID List looking for an entry >= the provided attribute value.
  1325. */
  1326. static PRUint32
  1327. vlv_trim_candidates_byvalue(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control)
  1328. {
  1329. PRUint32 si= 0; /* The Selected Index */
  1330. PRUint32 low= 0;
  1331. PRUint32 high= candidates->b_nids-1;
  1332. PRUint32 current= 0;
  1333. ID id = NOID;
  1334. int found= 0;
  1335. struct berval **typedown_value;
  1336. /* For non-matchrule indexing */
  1337. value_compare_fn_type compare_fn= NULL;
  1338. /*
  1339. * If the primary sorted attribute has an associated
  1340. * matching rule, then we must mangle the typedown
  1341. * value.
  1342. */
  1343. if (sort_control->matchrule==NULL)
  1344. {
  1345. void *pi= NULL;
  1346. if(slapi_attr_type2plugin(sort_control->type, &pi)==0)
  1347. {
  1348. struct berval *invalue[2];
  1349. invalue[0]= (struct berval *)&vlv_request_control->value; /* jcm: cast away const */
  1350. invalue[1]= NULL;
  1351. slapi_call_syntax_values2keys(pi,invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
  1352. plugin_call_syntax_get_compare_fn( pi, &compare_fn );
  1353. if (compare_fn == NULL) {
  1354. LDAPDebug(LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: "
  1355. "attempt to compare an unordered attribute",
  1356. 0, 0, 0);
  1357. compare_fn = slapi_berval_cmp;
  1358. }
  1359. }
  1360. }
  1361. else
  1362. {
  1363. typedown_value= vlv_create_matching_rule_value(sort_control->mr_pb,(struct berval *)&vlv_request_control->value);
  1364. compare_fn= slapi_berval_cmp;
  1365. }
  1366. retry:
  1367. /*
  1368. * Perform a binary search over the candidate list
  1369. */
  1370. if (0 == candidates->b_nids) { /* idlist is empty */
  1371. LDAPDebug( LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: Candidate ID List is empty.\n", 0, 0, 0 );
  1372. ber_bvecfree((struct berval**)typedown_value);
  1373. return candidates->b_nids; /* not found */
  1374. }
  1375. low= 0;
  1376. high= candidates->b_nids-1;
  1377. do {
  1378. int err= 0;
  1379. struct backentry *e= NULL;
  1380. if(!sort_control->order)
  1381. {
  1382. current = (low + high)/2;
  1383. }
  1384. else
  1385. {
  1386. current = (1 + low + high)/2;
  1387. }
  1388. id= candidates->b_ids[current];
  1389. e = id2entry( be, id, NULL, &err );
  1390. if ( e == NULL )
  1391. {
  1392. int rval;
  1393. LDAPDebug( LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: "
  1394. "Candidate ID %lu not found err=%d\n", (u_long)id, err, 0 );
  1395. rval = idl_delete((IDList **)&candidates, id);
  1396. if (0 == rval || 1 == rval || 2 == rval) {
  1397. goto retry;
  1398. } else {
  1399. ber_bvecfree((struct berval**)typedown_value);
  1400. return candidates->b_nids; /* not found */
  1401. }
  1402. }
  1403. else
  1404. {
  1405. /* Check if vlv_request_control->value is greater than or equal to the primary key. */
  1406. int match;
  1407. Slapi_Attr *attr;
  1408. if ( (NULL != compare_fn) && (slapi_entry_attr_find( e->ep_entry, sort_control->type, &attr ) == 0) )
  1409. {
  1410. /*
  1411. * If there's a matching rule associated with the primary
  1412. * attribute then use the indexer to mangle the attr values.
  1413. */
  1414. Slapi_Value **csn_value = valueset_get_valuearray(&attr->a_present_values);
  1415. struct berval **entry_value = /* xxxPINAKI needs modification attr->a_vals */NULL;
  1416. PRBool needFree = PR_FALSE;
  1417. if(sort_control->mr_pb!=NULL)
  1418. {
  1419. struct berval **tmp_entry_value = NULL;
  1420. valuearray_get_bervalarray(csn_value,&tmp_entry_value);
  1421. /* Matching rule. Do the magic mangling. Plugin owns the memory. */
  1422. matchrule_values_to_keys(sort_control->mr_pb,/* xxxPINAKI needs modification attr->a_vals */tmp_entry_value,&entry_value);
  1423. }
  1424. else
  1425. {
  1426. valuearray_get_bervalarray(csn_value,&entry_value);
  1427. needFree = PR_TRUE; /* entry_value is a copy */
  1428. }
  1429. if(!sort_control->order)
  1430. {
  1431. match= sort_attr_compare(entry_value, (struct berval**)typedown_value, compare_fn);
  1432. }
  1433. else
  1434. {
  1435. match= sort_attr_compare((struct berval**)typedown_value, entry_value, compare_fn);
  1436. }
  1437. if (needFree) {
  1438. ber_bvecfree((struct berval**)entry_value);
  1439. entry_value = NULL;
  1440. }
  1441. }
  1442. else
  1443. {
  1444. /*
  1445. * This attribute doesn't exist on this entry.
  1446. */
  1447. if(sort_control->order)
  1448. {
  1449. match= 1;
  1450. }
  1451. else
  1452. {
  1453. match= 0;
  1454. }
  1455. }
  1456. if(!sort_control->order)
  1457. {
  1458. if (match>=0)
  1459. {
  1460. high= current;
  1461. }
  1462. else
  1463. {
  1464. low= current+1;
  1465. }
  1466. }
  1467. else
  1468. {
  1469. if (match>=0)
  1470. {
  1471. high= current-1;
  1472. }
  1473. else
  1474. {
  1475. low= current;
  1476. }
  1477. }
  1478. if (low>=high)
  1479. {
  1480. found= 1;
  1481. si= high;
  1482. if(si==candidates->b_nids && !match)
  1483. {
  1484. /* Couldn't find an entry which matches the value, so return contentCount */
  1485. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates_byvalue: Not Found. Index %lu\n",si, 0, 0 );
  1486. si= candidates->b_nids;
  1487. }
  1488. else
  1489. {
  1490. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates_byvalue: Found. Index %lu\n",si, 0, 0 );
  1491. }
  1492. }
  1493. }
  1494. } while (!found);
  1495. ber_bvecfree((struct berval**)typedown_value);
  1496. return si;
  1497. }
  1498. /*
  1499. * Encode the VLV RESPONSE control.
  1500. *
  1501. * Create a virtual list view response control,
  1502. * and add it to the PBlock to be returned to the client.
  1503. *
  1504. * Returns:
  1505. * success ( 0 )
  1506. * operationsError (1),
  1507. */
  1508. int
  1509. vlv_make_response_control (Slapi_PBlock *pb, const struct vlv_response* vlvp)
  1510. {
  1511. BerElement *ber= NULL;
  1512. struct berval *bvp = NULL;
  1513. int rc = -1;
  1514. /*
  1515. VirtualListViewResponse ::= SEQUENCE {
  1516. targetPosition INTEGER (0 .. maxInt),
  1517. contentCount INTEGER (0 .. maxInt),
  1518. virtualListViewResult ENUMERATED {
  1519. success (0),
  1520. operationsError (1),
  1521. unwillingToPerform (53),
  1522. insufficientAccessRights (50),
  1523. busy (51),
  1524. timeLimitExceeded (3),
  1525. adminLimitExceeded (11),
  1526. sortControlMissing (60),
  1527. indexRangeError (61),
  1528. other (80) } }
  1529. */
  1530. if ( ( ber = ber_alloc()) == NULL )
  1531. {
  1532. return rc;
  1533. }
  1534. rc = ber_printf( ber, "{iie}", vlvp->targetPosition, vlvp->contentCount, vlvp->result );
  1535. if ( rc != -1 )
  1536. {
  1537. rc = ber_flatten( ber, &bvp );
  1538. }
  1539. ber_free( ber, 1 );
  1540. if ( rc != -1 )
  1541. {
  1542. LDAPControl new_ctrl = {0};
  1543. new_ctrl.ldctl_oid = LDAP_CONTROL_VLVRESPONSE;
  1544. new_ctrl.ldctl_value = *bvp;
  1545. new_ctrl.ldctl_iscritical = 1;
  1546. rc= slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &new_ctrl );
  1547. ber_bvfree(bvp);
  1548. }
  1549. LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_make_response_control: Index=%d Size=%d Result=%d\n", vlvp->targetPosition, vlvp->contentCount, vlvp->result );
  1550. return (rc==-1?LDAP_OPERATIONS_ERROR:LDAP_SUCCESS);
  1551. }
  1552. /*
  1553. * Generate a logging string for the vlv request and response
  1554. */
  1555. void vlv_print_access_log(Slapi_PBlock *pb,struct vlv_request* vlvi, struct vlv_response *vlvo)
  1556. {
  1557. #define VLV_LOG_BS (21*6 + 4 + 5) /* space for 20-digit values for all parameters + 'VLV ' + status */
  1558. char stack_buffer[VLV_LOG_BS];
  1559. char *buffer = stack_buffer;
  1560. char *p;
  1561. if (vlvi->value.bv_len > 20) {
  1562. buffer = slapi_ch_malloc(VLV_LOG_BS + vlvi->value.bv_len);
  1563. }
  1564. p = buffer;
  1565. p+= sprintf(p,"VLV ");
  1566. if (0 == vlvi->tag) {
  1567. /* By Index case */
  1568. p+= sprintf(p,"%d:%d:%d:%d",
  1569. vlvi->beforeCount ,
  1570. vlvi->afterCount ,
  1571. vlvi->index ,
  1572. vlvi->contentCount
  1573. );
  1574. } else {
  1575. /* By value case */
  1576. #define VLV_LOG_SS 32
  1577. char stack_string[VLV_LOG_SS];
  1578. char *string = stack_string;
  1579. if (vlvi->value.bv_len >= VLV_LOG_SS) {
  1580. string = slapi_ch_malloc(vlvi->value.bv_len+1);
  1581. }
  1582. strncpy(string,vlvi->value.bv_val,vlvi->value.bv_len);
  1583. string[vlvi->value.bv_len] = '\0';
  1584. p += sprintf(p,"%d:%d:%s",
  1585. vlvi->beforeCount ,
  1586. vlvi->afterCount ,
  1587. string
  1588. );
  1589. if (string != stack_string) {
  1590. slapi_ch_free( (void**)&string);
  1591. }
  1592. }
  1593. /* Now the response info */
  1594. p += sprintf(p," %d:%d (%d)",
  1595. vlvo->targetPosition ,
  1596. vlvo->contentCount,
  1597. vlvo->result
  1598. );
  1599. ldbm_log_access_message(pb,buffer);
  1600. if (buffer != stack_buffer) {
  1601. slapi_ch_free( (void**)&buffer);
  1602. }
  1603. }
  1604. /*
  1605. * Decode the VLV REQUEST control.
  1606. *
  1607. * If the client sends Index==0 we behave as if I=1
  1608. *
  1609. * Returns:
  1610. * success (0),
  1611. * operationsError (1),
  1612. *
  1613. */
  1614. int
  1615. vlv_parse_request_control( backend *be, struct berval *vlv_spec_ber,struct vlv_request* vlvp)
  1616. {
  1617. /* This control looks like this :
  1618. VirtualListViewRequest ::= SEQUENCE {
  1619. beforeCount INTEGER (0 .. maxInt),
  1620. afterCount INTEGER (0 .. maxInt),
  1621. CHOICE {
  1622. byIndex [0] SEQUENCE {
  1623. index INTEGER (0 .. maxInt),
  1624. contentCount INTEGER (0 .. maxInt) }
  1625. greaterThanOrEqual [1] assertionValue }
  1626. */
  1627. BerElement *ber = NULL;
  1628. int return_value = LDAP_SUCCESS;
  1629. vlvp->value.bv_len = 0;
  1630. vlvp->value.bv_val = NULL;
  1631. ber = ber_init(vlv_spec_ber);
  1632. if (ber_scanf(ber, "{ii", &vlvp->beforeCount, &vlvp->afterCount) == LBER_ERROR)
  1633. {
  1634. return_value= LDAP_OPERATIONS_ERROR;
  1635. }
  1636. else
  1637. {
  1638. LDAPDebug( LDAP_DEBUG_TRACE, "vlv_parse_request_control: Before=%d After=%d\n",
  1639. vlvp->beforeCount, vlvp->afterCount, 0 );
  1640. if (ber_scanf(ber,"t",&vlvp->tag) == LBER_ERROR)
  1641. {
  1642. return_value= LDAP_OPERATIONS_ERROR;
  1643. }
  1644. else
  1645. {
  1646. switch(vlvp->tag)
  1647. {
  1648. case LDAP_TAG_VLV_BY_INDEX:
  1649. /* byIndex */
  1650. vlvp->tag= 0;
  1651. if (ber_scanf(ber, "{ii}}", &vlvp->index, &vlvp->contentCount) == LBER_ERROR)
  1652. {
  1653. if (ISLEGACY(be)) {
  1654. return_value = LDAP_OPERATIONS_ERROR;
  1655. } else {
  1656. return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
  1657. }
  1658. }
  1659. else
  1660. {
  1661. /* Client Counts from 1. */
  1662. if(vlvp->index!=0)
  1663. {
  1664. vlvp->index--;
  1665. }
  1666. LDAPDebug( LDAP_DEBUG_TRACE, "vlv_parse_request_control: Index=%d Content=%d\n", vlvp->index, vlvp->contentCount, 0 );
  1667. }
  1668. break;
  1669. case LDAP_TAG_VLV_BY_VALUE:
  1670. /* byValue */
  1671. vlvp->tag= 1;
  1672. if (ber_scanf(ber,"o}",&vlvp->value) == LBER_ERROR)
  1673. {
  1674. if (ISLEGACY(be)) {
  1675. return_value = LDAP_OPERATIONS_ERROR;
  1676. } else {
  1677. return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
  1678. }
  1679. }
  1680. {
  1681. /* jcm: isn't there a utility fn to do this? */
  1682. char *p= slapi_ch_malloc(vlvp->value.bv_len+1);
  1683. strncpy(p,vlvp->value.bv_val,vlvp->value.bv_len);
  1684. p[vlvp->value.bv_len]= '\0';
  1685. LDAPDebug( LDAP_DEBUG_TRACE, "vlv_parse_request_control: Value=%s\n", p, 0, 0 );
  1686. slapi_ch_free( (void**)&p);
  1687. }
  1688. break;
  1689. default:
  1690. if (ISLEGACY(be)) {
  1691. return_value = LDAP_OPERATIONS_ERROR;
  1692. } else {
  1693. return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
  1694. }
  1695. }
  1696. }
  1697. }
  1698. /* the ber encoding is no longer needed */
  1699. ber_free(ber,1);
  1700. return return_value;
  1701. }
  1702. /* given a slapi_filter, check if there's a vlv index that matches that
  1703. * filter. if so, return the IDL for that index (else return NULL).
  1704. * -- a vlv index will match ONLY if that vlv index is subtree-scope and
  1705. * has the same search base and search filter.
  1706. * added read lock */
  1707. IDList *vlv_find_index_by_filter(struct backend *be, const char *base,
  1708. Slapi_Filter *f)
  1709. {
  1710. struct vlvSearch *t = NULL;
  1711. struct vlvIndex *vi;
  1712. Slapi_DN base_sdn;
  1713. PRUint32 length;
  1714. int err;
  1715. DB *db = NULL;
  1716. DBC *dbc = NULL;
  1717. IDList *idl;
  1718. Slapi_Filter *vlv_f;
  1719. slapi_sdn_init_dn_byref(&base_sdn, base);
  1720. PR_RWLock_Rlock(be->vlvSearchList_lock);
  1721. for (t = (struct vlvSearch *)be->vlvSearchList; t; t = t->vlv_next) {
  1722. /* all vlv "filters" start with (|(xxx)(objectclass=referral)).
  1723. * we only care about the (xxx) part.
  1724. */
  1725. vlv_f = t->vlv_slapifilter->f_or;
  1726. if ((t->vlv_scope == LDAP_SCOPE_SUBTREE) &&
  1727. (slapi_sdn_compare(t->vlv_base, &base_sdn) == 0) &&
  1728. (slapi_filter_compare(vlv_f, f) == 0)) {
  1729. /* found match! */
  1730. slapi_sdn_done(&base_sdn);
  1731. /* is there an index that's ready? */
  1732. vi = t->vlv_index;
  1733. while (!vlvIndex_online(vi) && vi) {
  1734. vi = vi->vlv_next;
  1735. }
  1736. if (!vi) {
  1737. /* no match */
  1738. LDAPDebug(LDAP_DEBUG_TRACE, "vlv: no index online for %s\n",
  1739. t->vlv_filter, 0, 0);
  1740. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1741. return NULL;
  1742. }
  1743. if (dblayer_get_index_file(be, vi->vlv_attrinfo, &db, 0) == 0) {
  1744. length = vlvIndex_get_indexlength(vi, db, 0 /* txn */);
  1745. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1746. err = db->cursor(db, 0 /* txn */, &dbc, 0);
  1747. if (err == 0) {
  1748. if (length == 0) /* 609377: index size could be 0 */
  1749. {
  1750. LDAPDebug(LDAP_DEBUG_TRACE, "vlv: index %s is empty\n",
  1751. t->vlv_filter, 0, 0);
  1752. idl = NULL;
  1753. }
  1754. else
  1755. {
  1756. err = vlv_build_idl(0, length-1, db, dbc, &idl, 1 /* dosort */);
  1757. }
  1758. dbc->c_close(dbc);
  1759. }
  1760. dblayer_release_index_file(be, vi->vlv_attrinfo, db);
  1761. if (err == 0) {
  1762. return idl;
  1763. } else {
  1764. LDAPDebug(LDAP_DEBUG_ANY, "vlv find index: err %d\n",
  1765. err, 0, 0);
  1766. return NULL;
  1767. }
  1768. }
  1769. }
  1770. }
  1771. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1772. /* no match */
  1773. slapi_sdn_done(&base_sdn);
  1774. return NULL;
  1775. }
  1776. /* replace c with c2 in string -- probably exists somewhere but I can't find it slapi maybe? */
  1777. static void replace_char(char *name, char c, char c2)
  1778. {
  1779. int x;
  1780. for (x = 0; name[x] != '\0'; x++) {
  1781. if (c == name[x]) {
  1782. name[x] = c2;
  1783. }
  1784. }
  1785. }
  1786. /* similar to what the console GUI does */
  1787. char *create_vlv_search_tag(const char* dn) {
  1788. char *tmp2=slapi_ch_strdup(dn);
  1789. replace_char(tmp2,',',' ');
  1790. replace_char(tmp2,'"','-');
  1791. replace_char(tmp2,'+','_');
  1792. return tmp2;
  1793. }
  1794. /* Builds strings from Slapi_DN similar console GUI. Uses those dns to
  1795. delete vlvsearch's if they match. New write lock.
  1796. */
  1797. #define LDBM_PLUGIN_ROOT ", cn=ldbm database, cn=plugins, cn=config"
  1798. #define TAG "cn=by MCC "
  1799. int vlv_delete_search_entry(Slapi_PBlock *pb, Slapi_Entry* e, ldbm_instance *inst)
  1800. {
  1801. int rc=0;
  1802. Slapi_PBlock *tmppb;
  1803. Slapi_DN *newdn;
  1804. struct vlvSearch* p=NULL;
  1805. char *buf, *buf2, *tag1, *tag2;
  1806. const char *dn= slapi_sdn_get_dn(&e->e_sdn);
  1807. backend *be= inst->inst_be;
  1808. if (instance_set_busy(inst) != 0)
  1809. {
  1810. LDAPDebug( LDAP_DEBUG_ANY,
  1811. "Backend instance: '%s' is already in the middle of "
  1812. "another task and cannot be disturbed.\n",
  1813. inst->inst_name, 0, 0);
  1814. return LDAP_OPERATIONS_ERROR;
  1815. }
  1816. tag1=create_vlv_search_tag(dn);
  1817. buf=slapi_ch_smprintf("%s%s%s%s%s","cn=MCC ",tag1,", cn=",inst->inst_name,LDBM_PLUGIN_ROOT);
  1818. newdn=slapi_sdn_new_dn_byval(buf);
  1819. /* vlvSearchList is modified; need Wlock */
  1820. PR_RWLock_Wlock(be->vlvSearchList_lock);
  1821. p = vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, newdn);
  1822. if(p!=NULL)
  1823. {
  1824. LDAPDebug( LDAP_DEBUG_ANY, "Deleted Virtual List View Search (%s).\n", p->vlv_name, 0, 0);
  1825. tag2=create_vlv_search_tag(dn);
  1826. buf2=slapi_ch_smprintf("%s%s,%s",TAG,tag2,buf);
  1827. vlvSearch_removefromlist((struct vlvSearch **)&be->vlvSearchList,p->vlv_dn);
  1828. /* This line release lock to prevent recursive deadlock caused by slapi_internal_delete calling vlvDeleteSearchEntry */
  1829. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1830. vlvSearch_delete(&p);
  1831. tmppb = slapi_pblock_new();
  1832. slapi_delete_internal_set_pb(tmppb, buf2, NULL, NULL,
  1833. (void *)plugin_get_default_component_id(), 0);
  1834. slapi_delete_internal_pb(tmppb);
  1835. slapi_pblock_get (tmppb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1836. if(rc != LDAP_SUCCESS) {
  1837. LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", buf2, 0, 0);
  1838. }
  1839. pblock_done(tmppb);
  1840. pblock_init(tmppb);
  1841. slapi_delete_internal_set_pb(tmppb, buf, NULL, NULL,
  1842. (void *)plugin_get_default_component_id(), 0);
  1843. slapi_delete_internal_pb(tmppb);
  1844. slapi_pblock_get (tmppb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1845. if(rc != LDAP_SUCCESS) {
  1846. LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", buf, 0, 0);
  1847. }
  1848. slapi_pblock_destroy(tmppb);
  1849. slapi_ch_free((void **)&tag2);
  1850. slapi_ch_free((void **)&buf2);
  1851. } else {
  1852. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1853. }
  1854. instance_set_not_busy(inst);
  1855. slapi_ch_free((void **)&tag1);
  1856. slapi_ch_free((void **)&buf);
  1857. slapi_sdn_free(&newdn);
  1858. return rc;
  1859. }
  1860. void
  1861. vlv_acquire_lock(backend *be)
  1862. {
  1863. LDAPDebug(LDAP_DEBUG_TRACE, "vlv_acquire_lock => trying to acquire the lock\n", 0, 0, 0);
  1864. PR_RWLock_Wlock(be->vlvSearchList_lock);
  1865. }
  1866. void
  1867. vlv_release_lock(backend *be)
  1868. {
  1869. LDAPDebug(LDAP_DEBUG_TRACE, "vlv_release_lock => trying to release the lock\n", 0, 0, 0);
  1870. PR_RWLock_Unlock(be->vlvSearchList_lock);
  1871. }