sort.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  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. /* Code to implement result sorting */
  42. #include "back-ldbm.h"
  43. #define CHECK_INTERVAL 10 /* The frequency whith which we'll check the admin limits */
  44. /* Structure to carry the things we need down the call stack */
  45. struct baggage_carrier {
  46. backend *be; /* For id2entry */
  47. Slapi_PBlock *pb; /* For slapi_op_abandoned */
  48. time_t stoptime; /* For timelimit policing */
  49. int lookthrough_limit;
  50. int check_counter; /* Used to avoid checking every 100ns */
  51. };
  52. typedef struct baggage_carrier baggage_carrier;
  53. static int slapd_qsort (baggage_carrier *bc,IDList *list,sort_spec *s);
  54. static int print_out_sort_spec(char* buffer,sort_spec *s,int *size);
  55. static void sort_spec_thing_free(sort_spec_thing *s)
  56. {
  57. if (NULL != s->type) {
  58. slapi_ch_free((void **)&s->type);
  59. }
  60. if (NULL != s->matchrule) {
  61. slapi_ch_free( (void**)&s->matchrule);
  62. }
  63. if (NULL != s->mr_pb) {
  64. destroy_matchrule_indexer(s->mr_pb);
  65. slapi_pblock_destroy (s->mr_pb);
  66. }
  67. slapi_ch_free( (void**)&s);
  68. }
  69. static sort_spec_thing *sort_spec_thing_allocate()
  70. {
  71. return (sort_spec_thing *) slapi_ch_calloc(1,sizeof (sort_spec_thing));
  72. }
  73. void sort_spec_free(sort_spec *s)
  74. {
  75. /* Walk down the list freeing */
  76. sort_spec_thing *t = (sort_spec_thing*)s;
  77. sort_spec_thing *p = NULL;
  78. do {
  79. p = t->next;
  80. sort_spec_thing_free(t);
  81. t = p;
  82. } while (p);
  83. }
  84. static sort_spec_thing * sort_spec_thing_new(char *type, char* matchrule, int reverse)
  85. {
  86. sort_spec_thing *s = sort_spec_thing_allocate();
  87. if (NULL == s) {
  88. return s;
  89. }
  90. s->type = type;
  91. s->matchrule = matchrule;
  92. s->order = reverse;
  93. return s;
  94. }
  95. void sort_log_access(Slapi_PBlock *pb,sort_spec_thing *s,IDList *candidates)
  96. {
  97. #define SORT_LOG_BSZ 64
  98. #define SORT_LOG_PAD 22 /* space for the number of candidates */
  99. char stack_buffer[SORT_LOG_BSZ + SORT_LOG_PAD];
  100. char *buffer = NULL;
  101. int ret = 0;
  102. int size = SORT_LOG_BSZ + SORT_LOG_PAD;
  103. char *prefix = "SORT ";
  104. int prefix_size = strlen(prefix);
  105. char candidate_buffer[32]; /* store u_long value; max 20 digits */
  106. int candidate_size = 0;
  107. buffer = stack_buffer;
  108. size -= PR_snprintf(buffer,sizeof(stack_buffer),"%s",prefix);
  109. if (candidates) {
  110. if (ALLIDS(candidates)) {
  111. PR_snprintf(candidate_buffer, sizeof(candidate_buffer), "(*)");
  112. candidate_size = strlen(candidate_buffer);
  113. } else {
  114. PR_snprintf(candidate_buffer, sizeof(candidate_buffer),
  115. "(%lu)", (u_long)candidates->b_nids);
  116. candidate_size = strlen(candidate_buffer);
  117. }
  118. }
  119. size -= (candidate_size + 1); /* 1 for '\0' */
  120. ret = print_out_sort_spec(buffer+prefix_size,s,&size);
  121. if (0 != ret) {
  122. /* It wouldn't fit in the buffer */
  123. buffer =
  124. slapi_ch_malloc(prefix_size + size + candidate_size + SORT_LOG_PAD);
  125. sprintf(buffer,"%s",prefix);
  126. ret = print_out_sort_spec(buffer+prefix_size,s,&size);
  127. }
  128. if (0 == ret && candidates) {
  129. sprintf(buffer+size+prefix_size, "%s", candidate_buffer);
  130. }
  131. /* Now output it */
  132. ldbm_log_access_message(pb,buffer);
  133. if (buffer != stack_buffer) {
  134. slapi_ch_free( (void**)&buffer);
  135. }
  136. }
  137. /* Fix for bug # 394184, SD, 20 Jul 00 */
  138. /* replace the hard coded return value by the appropriate LDAP error code */
  139. /* also removed an useless if (0 == return_value) {} statement */
  140. /* Given a candidate list and a list of sort order specifications, sort this, or cop out */
  141. /* Returns: 0 -- sorted OK now is: LDAP_SUCCESS (fix for bug #394184)
  142. * -1 -- protocol error now is: LDAP_PROTOCOL_ERROR
  143. * -2 -- too hard to sort these now is: LDAP_UNWILLING_TO_PERFORM
  144. * -3 -- operation error now is: LDAP_OPERATIONS_ERROR
  145. * -4 -- timeout now is: LDAP_TIMELIMIT_EXCEEDED
  146. * -5 -- admin limit exceeded now is: LDAP_ADMINLIMIT_EXCEEDED
  147. * -6 -- abandoned now is: LDAP_OTHER
  148. */
  149. /*
  150. * So here's the plan:
  151. * Plan A: We do a regular quicksort on the entries.
  152. * Plan B: Through some hint given us from on high, we
  153. * determine that the entries are _already_
  154. * sorted as requested, thus we do nothing !
  155. * Plan C: We determine that sorting these suckers is
  156. * far too hard for us to even try, so we refuse.
  157. */
  158. int sort_candidates(backend *be,int lookthrough_limit,time_t time_up, Slapi_PBlock *pb,
  159. IDList *candidates, sort_spec_thing *s, char **sort_error_type)
  160. {
  161. int return_value = LDAP_SUCCESS;
  162. baggage_carrier bc = {0};
  163. sort_spec_thing *this_s = NULL;
  164. /* We refuse to sort a non-existent IDlist */
  165. if (NULL == candidates) {
  166. return LDAP_UNWILLING_TO_PERFORM;
  167. }
  168. /* we refuse to sort a candidate list which is vast */
  169. if (ALLIDS(candidates)) {
  170. LDAPDebug( LDAP_DEBUG_TRACE, "Asked to sort ALLIDS candidate list, refusing\n",0, 0, 0 );
  171. return LDAP_UNWILLING_TO_PERFORM;
  172. }
  173. /* Iterate over the sort types */
  174. for (this_s = s; this_s; this_s=this_s->next) {
  175. if (NULL == this_s->matchrule) {
  176. void *pi;
  177. int return_value = 0;
  178. return_value = slapi_attr_type2plugin( this_s->type, &pi );
  179. if (0 == return_value) {
  180. return_value = plugin_call_syntax_get_compare_fn( pi, &(this_s->compare_fn) );
  181. }
  182. if (return_value != 0 ) {
  183. LDAPDebug( LDAP_DEBUG_TRACE, "Attempting to sort a non-ordered attribute (%s)\n",this_s->type, 0, 0 );
  184. /* DBDB we should set the error type here */
  185. return_value = LDAP_UNWILLING_TO_PERFORM;
  186. *sort_error_type = this_s->type;
  187. return return_value;
  188. }
  189. } else {
  190. /* Need to---find the matching rule plugin,
  191. * tell it it needs to do ordering for this OID
  192. * see whether it agrees---if not signal error to client
  193. * Then later use it for generating ordering keys.
  194. * finally, free it up
  195. */
  196. return_value = create_matchrule_indexer(&this_s->mr_pb,this_s->matchrule,this_s->type);
  197. if (LDAP_SUCCESS != return_value) {
  198. *sort_error_type = this_s->type;
  199. return return_value;
  200. }
  201. this_s->compare_fn = slapi_berval_cmp;
  202. }
  203. }
  204. bc.be = be;
  205. bc.pb = pb;
  206. bc.stoptime = time_up;
  207. bc.lookthrough_limit = lookthrough_limit;
  208. bc.check_counter = 1;
  209. return_value = slapd_qsort(&bc,candidates,s);
  210. LDAPDebug( LDAP_DEBUG_TRACE, "<= Sorting done\n",0, 0, 0 );
  211. return return_value;
  212. }
  213. /* End fix for bug # 394184 */
  214. static int term_tag(ber_tag_t tag)
  215. {
  216. return ( (LBER_END_OF_SEQORSET == tag) || (LBER_ERROR == tag) );
  217. }
  218. /* hacky function to convert a sort spec to a string
  219. you specify a buffer and a size. If the thing won't fit, it returns
  220. non-zero, and the size needed. Pass NULL buffer to just get the size */
  221. static int print_out_sort_spec(char* buffer,sort_spec *s,int *size)
  222. {
  223. /* Walk down the list printing */
  224. sort_spec_thing *t = (sort_spec_thing*)s;
  225. sort_spec_thing *p = NULL;
  226. int buffer_size = 0;
  227. int input_size = 0;
  228. if (NULL != size) {
  229. input_size = *size;
  230. }
  231. do {
  232. p = t->next;
  233. buffer_size += strlen(t->type);
  234. if (t->order) {
  235. buffer_size += 1; /* For the '-' */
  236. }
  237. if (NULL != t->matchrule) {
  238. /* space for matchrule + semicolon */
  239. buffer_size += strlen(t->matchrule) + 1;
  240. }
  241. buffer_size += 1; /* for the space */
  242. if ( (NULL != buffer) && (buffer_size <= input_size) ) {
  243. /* write into the buffer */
  244. buffer += sprintf(buffer,"%s%s%s%s ",
  245. t->order ? "-" : "",
  246. t->type,
  247. ( NULL == t->matchrule ) ? "" : ";",
  248. ( NULL == t->matchrule ) ? "" : t->matchrule);
  249. }
  250. t = p;
  251. } while (p);
  252. if (NULL != size) {
  253. *size = buffer_size;
  254. }
  255. if (buffer_size <= input_size) {
  256. return 0;
  257. } else {
  258. return 1;
  259. }
  260. }
  261. int parse_sort_spec(struct berval *sort_spec_ber, sort_spec **ps)
  262. {
  263. /* So here we call ber_scanf to get the sort spec */
  264. /* This control looks like this :
  265. SortKeyList ::= SEQUENCE OF SEQUENCE {
  266. attributeType AttributeType,
  267. orderingRule [0] MatchingRuleId OPTIONAL,
  268. reverseOrder [1] BOOLEAN DEFAULT FALSE }
  269. */
  270. BerElement *ber = NULL;
  271. sort_spec_thing *listhead = NULL;
  272. ber_tag_t tag = 0;
  273. ber_len_t len = -1;
  274. char *last = NULL;
  275. sort_spec_thing *listpointer = NULL;
  276. char *type = NULL;
  277. char *matchrule = NULL;
  278. int rc = LDAP_SUCCESS;
  279. ber = ber_init(sort_spec_ber);
  280. if(ber==NULL)
  281. {
  282. return -1;
  283. }
  284. /* Work our way along the BER, one sort spec at a time */
  285. for ( tag = ber_first_element( ber, &len, &last ); !term_tag(tag); tag = ber_next_element( ber, &len, last )) {
  286. /* we're now pointing at the beginning of a sequence of type, matching rule and reverse indicator */
  287. char *inner_last = NULL;
  288. char *rtype = NULL;
  289. int reverse = 0;
  290. ber_tag_t next_tag = 0;
  291. sort_spec_thing *s = NULL;
  292. ber_tag_t return_value;
  293. len = -1; /* reset - not used here */
  294. next_tag = ber_first_element( ber, &len, &inner_last );
  295. /* The type is not optional */
  296. return_value = ber_scanf(ber,"a",&rtype);
  297. if (LBER_ERROR == return_value) {
  298. slapi_ch_free_string(&rtype);
  299. rc = LDAP_PROTOCOL_ERROR;
  300. goto err;
  301. }
  302. /* normalize */
  303. type = slapi_attr_syntax_normalize(rtype);
  304. slapi_ch_free_string(&rtype);
  305. /* Now look for the next tag. */
  306. len = -1; /* reset - not used here */
  307. next_tag = ber_next_element(ber,&len, inner_last);
  308. /* Are we done ? */
  309. if ( !term_tag(next_tag) ) {
  310. /* Is it the matching rule ? */
  311. if (LDAP_TAG_SK_MATCHRULE == next_tag) {
  312. /* If so, get it */
  313. ber_scanf(ber,"a",&matchrule);
  314. /* That can be followed by a reverse indicator */
  315. len = -1; /* reset - not used here */
  316. next_tag = ber_next_element(ber,&len, inner_last);
  317. if (LDAP_TAG_SK_REVERSE == next_tag) {
  318. /* Get the reverse sort indicator here */
  319. ber_scanf(ber,"b",&reverse);
  320. /* The protocol police say--"You must have other than your default value" */
  321. if (0 == reverse) {
  322. /* Protocol error */
  323. rc = LDAP_PROTOCOL_ERROR;
  324. goto err;
  325. }
  326. } else {
  327. /* Perhaps we're done now ? */
  328. if ((LBER_END_OF_SEQORSET != next_tag) && (len != -1)) {
  329. /* Protocol error---we got a matching rule, but followed by something other
  330. * than reverse or end of sequence.
  331. */
  332. rc = LDAP_PROTOCOL_ERROR;
  333. goto err;
  334. }
  335. }
  336. } else {
  337. /* Is it the reverse indicator ? */
  338. if (LDAP_TAG_SK_REVERSE == next_tag) {
  339. /* If so, get it */
  340. ber_scanf(ber,"b",&reverse);
  341. } else {
  342. /* Protocol error---tag which isn't either of the legal ones came first */
  343. rc = LDAP_PROTOCOL_ERROR;
  344. goto err;
  345. }
  346. }
  347. }
  348. s = sort_spec_thing_new(type,matchrule,reverse);
  349. if (NULL == s) {
  350. /* Memory allocation failed */
  351. rc = LDAP_OPERATIONS_ERROR;
  352. goto err;
  353. }
  354. type = matchrule = NULL;
  355. if (NULL != listpointer) {
  356. listpointer->next = s;
  357. }
  358. listpointer = s;
  359. if (NULL == listhead) {
  360. listhead = s;
  361. }
  362. len = -1; /* reset for next loop iter */
  363. }
  364. if (NULL == listhead) { /* LP - defect #559792 - don't return null listhead */
  365. *ps = NULL;
  366. rc = LDAP_PROTOCOL_ERROR;
  367. goto err;
  368. }
  369. /* the ber encoding is no longer needed */
  370. ber_free(ber,1);
  371. *ps = (sort_spec *)listhead;
  372. return LDAP_SUCCESS;
  373. err:
  374. if (listhead) sort_spec_free((sort_spec*) listhead);
  375. slapi_ch_free((void**)&type);
  376. slapi_ch_free((void**)&matchrule);
  377. ber_free(ber,1);
  378. return rc;
  379. }
  380. #if 0
  381. static int attr_value_compare(struct berval *value_a, struct berval *value_b)
  382. {
  383. /* return value_cmp(value_a,value_b,syntax,3); */
  384. return strcasecmp(value_a->bv_val, value_b->bv_val);
  385. }
  386. #endif
  387. struct berval* attr_value_lowest(struct berval **values, value_compare_fn_type compare_fn)
  388. {
  389. /* We iterate through the values, storing our last best guess as to the lowest */
  390. struct berval *lowest_so_far = values[0];
  391. struct berval *this_one = NULL;
  392. for (this_one = *values; this_one; this_one = *values++) {
  393. if (compare_fn(lowest_so_far,this_one) > 0) {
  394. lowest_so_far = this_one;
  395. }
  396. }
  397. return lowest_so_far;
  398. }
  399. int sort_attr_compare(struct berval ** value_a, struct berval ** value_b, value_compare_fn_type compare_fn)
  400. {
  401. /* So, the thing we need to do here is to look out for multi-valued
  402. * attributes. When we get one of those, we need to look through all the
  403. * values to find the lowest one (per X.511 edict). We then use that one to
  404. * compare against the other. We should really put some logic in here to
  405. * prevent us partying on an attribute with thousands of values for a long time.
  406. */
  407. struct berval *compare_value_a = NULL;
  408. struct berval *compare_value_b = NULL;
  409. compare_value_a = attr_value_lowest(value_a, compare_fn);
  410. compare_value_b = attr_value_lowest(value_b, compare_fn);
  411. return compare_fn(compare_value_a,compare_value_b);
  412. }
  413. #if 0
  414. /* USE THE _SV VERSION NOW */
  415. /* Comparison routine, called by qsort.
  416. * The job here is to return the correct value
  417. * for the operation a < b
  418. * Returns:
  419. * <0 when a < b
  420. * 0 when a == b
  421. * >0 when a > b
  422. */
  423. static int compare_entries(ID *id_a, ID *id_b, sort_spec *s,baggage_carrier *bc, int *error)
  424. {
  425. /* We get passed the IDs, but need to fetch the entries in order to
  426. * perform the comparison .
  427. */
  428. struct backentry *a = NULL;
  429. struct backentry *b = NULL;
  430. int result = 0;
  431. sort_spec_thing *this_one = NULL;
  432. int return_value = -1;
  433. backend *be = bc->be;
  434. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  435. int err;
  436. *error = 1;
  437. a = id2entry(be,*id_a,NULL,&err);
  438. if (NULL == a) {
  439. if (0 != err ) {
  440. LDAPDebug(LDAP_DEBUG_ANY,"compare_entries db err %d\n",err,0,0);
  441. }
  442. /* Were up a creek without paddle here */
  443. /* Best to log error and set some flag */
  444. return 0;
  445. }
  446. b = id2entry(be,*id_b,NULL,&err);
  447. if (NULL == b) {
  448. if (0 != err ) {
  449. LDAPDebug(LDAP_DEBUG_ANY,"compare_entries db err %d\n",err,0,0);
  450. }
  451. return 0;
  452. }
  453. /* OK, now we have the entries, so we work our way down the attribute list comparing as we go */
  454. for (this_one = (sort_spec_thing*)s; this_one ; this_one = this_one->next) {
  455. char *type = this_one->type;
  456. int order = this_one->order;
  457. Slapi_Attr *attr_a = NULL;
  458. Slapi_Attr *attr_b = NULL;
  459. struct berval **value_a = NULL;
  460. struct berval **value_b = NULL;
  461. /* Get the two attribute values from the entries */
  462. return_value = slapi_entry_attr_find(a->ep_entry,type,&attr_a);
  463. return_value = slapi_entry_attr_find(b->ep_entry,type,&attr_b);
  464. /* What do we do if one or more of the entries lacks this attribute ? */
  465. /* if one lacks the attribute */
  466. if (NULL == attr_a) {
  467. /* then if the other does too, they're equal */
  468. if (NULL == attr_b) {
  469. result = 0;
  470. continue;
  471. } else
  472. {
  473. /* If one has the attribute, and the other
  474. * doesn't, the missing attribute is the
  475. * LARGER one. (bug #108154) -robey
  476. */
  477. result = 1;
  478. break;
  479. }
  480. }
  481. if (NULL == attr_b) {
  482. result = -1;
  483. break;
  484. }
  485. /* Somewhere in here, we need to go sideways for match rule case
  486. * we need to call the match rule plugin to get the attribute values
  487. * converted into ordering keys. Then we proceed as usual to use those,
  488. * but ensuring that we don't leak memory anywhere. This works as follows:
  489. * the code assumes that the attrs are references into the entry, so
  490. * doesn't try to free them. We need to note at the right place that
  491. * we're on the matchrule path, and accordingly free the keys---this turns out
  492. * to be when we free the indexer */
  493. if (NULL == s->matchrule) {
  494. /* Non-match rule case */
  495. /* xxxPINAKI
  496. needs modification
  497. value_a = attr_a->a_vals;
  498. value_b = attr_b->a_vals;
  499. */
  500. } else {
  501. /* Match rule case */
  502. struct berval **actual_value_b = NULL;
  503. struct berval **temp_value = NULL;
  504. /* xxxPINAKI
  505. needs modification
  506. struct berval **actual_value_a = NULL;
  507. actual_value_a = attr_a->a_vals;
  508. actual_value_b = attr_b->a_vals;
  509. matchrule_values_to_keys(s->mr_pb,actual_value_a,&temp_value);
  510. */
  511. /* Now copy it, so the second call doesn't crap on it */
  512. value_a = slapi_ch_bvecdup(temp_value); /* Really, we'd prefer to not call the chXXX variant...*/
  513. matchrule_values_to_keys(s->mr_pb,actual_value_b,&value_b);
  514. }
  515. /* Compare them */
  516. if (!order) {
  517. result = sort_attr_compare(value_a, value_b, s->compare_fn);
  518. } else {
  519. /* If reverse, invert the sense of the comparison */
  520. result = sort_attr_compare(value_b, value_a, s->compare_fn);
  521. }
  522. /* Time to free up the attribute allocated above */
  523. if (NULL != s->matchrule) {
  524. ber_bvecfree(value_a);
  525. }
  526. /* Are they equal ? */
  527. if (0 != result) {
  528. /* If not, we're done */
  529. break;
  530. }
  531. /* If so, proceed to the next attribute for comparison */
  532. }
  533. cache_return(&inst->inst_cache,&a);
  534. cache_return(&inst->inst_cache,&b);
  535. *error = 0;
  536. return result;
  537. }
  538. #endif
  539. /* Comparison routine, called by qsort.
  540. * The job here is to return the correct value
  541. * for the operation a < b
  542. * Returns:
  543. * <0 when a < b
  544. * 0 when a == b
  545. * >0 when a > b
  546. */
  547. static int compare_entries_sv(ID *id_a, ID *id_b, sort_spec *s,baggage_carrier *bc, int *error)
  548. {
  549. /* We get passed the IDs, but need to fetch the entries in order to
  550. * perform the comparison .
  551. */
  552. struct backentry *a = NULL;
  553. struct backentry *b = NULL;
  554. int result = 0;
  555. sort_spec_thing *this_one = NULL;
  556. backend *be = bc->be;
  557. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  558. int err;
  559. *error = 1;
  560. a = id2entry(be,*id_a,NULL,&err);
  561. if (NULL == a) {
  562. if (0 != err ) {
  563. LDAPDebug(LDAP_DEBUG_TRACE,"compare_entries db err %d\n",err,0,0);
  564. }
  565. /* Were up a creek without paddle here */
  566. /* Best to log error and set some flag */
  567. return 0;
  568. }
  569. b = id2entry(be,*id_b,NULL,&err);
  570. if (NULL == b) {
  571. if (0 != err ) {
  572. LDAPDebug(LDAP_DEBUG_TRACE,"compare_entries db err %d\n",err,0,0);
  573. }
  574. return 0;
  575. }
  576. /* OK, now we have the entries, so we work our way down the attribute list comparing as we go */
  577. for (this_one = (sort_spec_thing*)s; this_one ; this_one = this_one->next) {
  578. char *type = this_one->type;
  579. int order = this_one->order;
  580. Slapi_Attr *attr_a = NULL;
  581. Slapi_Attr *attr_b = NULL;
  582. struct berval **value_a = NULL;
  583. struct berval **value_b = NULL;
  584. /* Get the two attribute values from the entries */
  585. slapi_entry_attr_find(a->ep_entry,type,&attr_a);
  586. slapi_entry_attr_find(b->ep_entry,type,&attr_b);
  587. /* What do we do if one or more of the entries lacks this attribute ? */
  588. /* if one lacks the attribute */
  589. if (NULL == attr_a) {
  590. /* then if the other does too, they're equal */
  591. if (NULL == attr_b) {
  592. result = 0;
  593. continue;
  594. } else
  595. {
  596. /* If one has the attribute, and the other
  597. * doesn't, the missing attribute is the
  598. * LARGER one. (bug #108154) -robey
  599. */
  600. result = 1;
  601. break;
  602. }
  603. }
  604. if (NULL == attr_b) {
  605. result = -1;
  606. break;
  607. }
  608. /* Somewhere in here, we need to go sideways for match rule case
  609. * we need to call the match rule plugin to get the attribute values
  610. * converted into ordering keys. Then we proceed as usual to use those,
  611. * but ensuring that we don't leak memory anywhere. This works as follows:
  612. * the code assumes that the attrs are references into the entry, so
  613. * doesn't try to free them. We need to note at the right place that
  614. * we're on the matchrule path, and accordingly free the keys---this turns out
  615. * to be when we free the indexer */
  616. if (NULL == s->matchrule) {
  617. /* Non-match rule case */
  618. valuearray_get_bervalarray(valueset_get_valuearray(&attr_a->a_present_values),&value_a);
  619. valuearray_get_bervalarray(valueset_get_valuearray(&attr_b->a_present_values),&value_b);
  620. } else {
  621. /* Match rule case */
  622. struct berval **actual_value_a = NULL;
  623. struct berval **actual_value_b = NULL;
  624. struct berval **temp_value = NULL;
  625. valuearray_get_bervalarray(valueset_get_valuearray(&attr_a->a_present_values),&actual_value_a);
  626. valuearray_get_bervalarray(valueset_get_valuearray(&attr_b->a_present_values),&actual_value_b);
  627. matchrule_values_to_keys(s->mr_pb,actual_value_a,&temp_value);
  628. /* Now copy it, so the second call doesn't crap on it */
  629. value_a = slapi_ch_bvecdup(temp_value); /* Really, we'd prefer to not call the chXXX variant...*/
  630. matchrule_values_to_keys(s->mr_pb,actual_value_b,&value_b);
  631. if (actual_value_a) ber_bvecfree(actual_value_a);
  632. if (actual_value_b) ber_bvecfree(actual_value_b);
  633. }
  634. /* Compare them */
  635. if (!order) {
  636. result = sort_attr_compare(value_a, value_b, s->compare_fn);
  637. } else {
  638. /* If reverse, invert the sense of the comparison */
  639. result = sort_attr_compare(value_b, value_a, s->compare_fn);
  640. }
  641. /* Time to free up the attributes allocated above */
  642. if (NULL != s->matchrule) {
  643. ber_bvecfree(value_a);
  644. } else {
  645. ber_bvecfree(value_a);
  646. ber_bvecfree(value_b);
  647. }
  648. /* Are they equal ? */
  649. if (0 != result) {
  650. /* If not, we're done */
  651. break;
  652. }
  653. /* If so, proceed to the next attribute for comparison */
  654. }
  655. cache_return(&inst->inst_cache,&a);
  656. cache_return(&inst->inst_cache,&b);
  657. *error = 0;
  658. return result;
  659. }
  660. /* Fix for bug # 394184, SD, 20 Jul 00 */
  661. /* replace the hard coded return value by the appropriate LDAP error code */
  662. /*
  663. * Returns:
  664. * 0: Everything OK now is: LDAP_SUCCESS (fix for bug #394184)
  665. * -1: A protocol error now is: LDAP_PROTOCOL_ERROR
  666. * -2: Too hard now is: LDAP_UNWILLING_TO_PERFORM
  667. * -3: Operation error now is: LDAP_OPERATIONS_ERROR
  668. * -4: Timeout now is: LDAP_TIMELIMIT_EXCEEDED
  669. * -5: Admin limit exceeded now is: LDAP_ADMINLIMIT_EXCEEDED
  670. * -6: Abandoned now is: LDAP_OTHER
  671. */
  672. static int sort_check(baggage_carrier *bc)
  673. {
  674. time_t curtime = 0;
  675. /* check for abandon */
  676. if ( slapi_op_abandoned( bc->pb)) {
  677. return LDAP_OTHER;
  678. }
  679. /* Check to see if our journey is really necessary */
  680. if (0 == ((bc->check_counter)++ % CHECK_INTERVAL) ) {
  681. /* check time limit */
  682. curtime = current_time();
  683. if ( bc->stoptime != -1 && curtime > bc->stoptime ) {
  684. return LDAP_TIMELIMIT_EXCEEDED;
  685. }
  686. /* Fix for bugid #394184, SD, 05 Jul 00 */
  687. /* not sure this is the appropriate place to do this;
  688. since the entries are swaped in slapd_qsort, some of them are most
  689. probably counted more than once */
  690. /* hence commenting out the following test and moving it into slapd_qsort */
  691. /* check lookthrough limit */
  692. /* if ( bc->lookthrough_limit != -1 && (bc->lookthrough_limit -= CHECK_INTERVAL) < 0 ) {
  693. return LDAP_ADMINLIMIT_EXCEEDED;
  694. } */
  695. /* end for bugid #394184 */
  696. }
  697. return LDAP_SUCCESS;
  698. }
  699. /* End fix for bug # 394184 */
  700. /* prototypes for local routines */
  701. static void shortsort(baggage_carrier *bc,ID *lo, ID *hi,sort_spec *s );
  702. static void swap (ID *a,ID *b);
  703. /* this parameter defines the cutoff between using quick sort and
  704. insertion sort for arrays; arrays with lengths shorter or equal to the
  705. below value use insertion sort */
  706. #define CUTOFF 8 /* testing shows that this is good value */
  707. /* Fix for bug # 394184, SD, 20 Jul 00 */
  708. /* replace the hard coded return value by the appropriate LDAP error code */
  709. /* Our qsort needs to police the client timeout and lookthrough limit ?
  710. * It knows how to compare entries, so we don't bother with all the void * stuff.
  711. */
  712. /*
  713. * Returns:
  714. * 0: Everything OK now is: LDAP_SUCCESS (fix for bug #394184)
  715. * -1: A protocol error now is: LDAP_PROTOCOL_ERROR
  716. * -2: Too hard now is: LDAP_UNWILLING_TO_PERFORM
  717. * -3: Operation error now is: LDAP_OPERATIONS_ERROR
  718. * -4: Timeout now is: LDAP_TIMELIMIT_EXCEEDED
  719. * -5: Admin limit exceeded now is: LDAP_ADMINLIMIT_EXCEEDED
  720. * -6: Abandoned now is: LDAP_OTHER
  721. */
  722. static int slapd_qsort(baggage_carrier *bc,IDList *list, sort_spec *s)
  723. {
  724. ID *lo, *hi; /* ends of sub-array currently sorting */
  725. ID *mid; /* points to middle of subarray */
  726. ID *loguy, *higuy; /* traveling pointers for partition step */
  727. NIDS size; /* size of the sub-array */
  728. ID *lostk[30], *histk[30];
  729. int stkptr; /* stack for saving sub-array to be processed */
  730. NIDS num = list->b_nids;
  731. int return_value = LDAP_SUCCESS;
  732. int error = 0;
  733. /* Note: the number of stack entries required is no more than
  734. 1 + log2(size), so 30 is sufficient for any array */
  735. if (num < 2 )
  736. return LDAP_SUCCESS; /* nothing to do */
  737. stkptr = 0; /* initialize stack */
  738. lo = &(list->b_ids[0]);
  739. hi = &(list->b_ids[num-1]); /* initialize limits */
  740. /* Fix for bugid #394184, SD, 20 Jul 00 */
  741. if ( bc->lookthrough_limit != -1 && ( bc->lookthrough_limit <= (int) list->b_nids) ) {
  742. return LDAP_ADMINLIMIT_EXCEEDED;
  743. }
  744. /* end Fix for bugid #394184 */
  745. /* this entry point is for pseudo-recursion calling: setting
  746. lo and hi and jumping to here is like recursion, but stkptr is
  747. prserved, locals aren't, so we preserve stuff on the stack */
  748. recurse:
  749. size = (hi - lo) + 1; /* number of el's to sort */
  750. /* below a certain size, it is faster to use a O(n^2) sorting method */
  751. if (size <= CUTOFF) {
  752. shortsort(bc,lo, hi, s );
  753. }
  754. else {
  755. /* First we pick a partititioning element. The efficiency of the
  756. algorithm demands that we find one that is approximately the
  757. median of the values, but also that we select one fast. Using
  758. the first one produces bad performace if the array is already
  759. sorted, so we use the middle one, which would require a very
  760. wierdly arranged array for worst case performance. Testing shows
  761. that a median-of-three algorithm does not, in general, increase
  762. performance. */
  763. mid = lo + (size / 2); /* find middle element */
  764. swap(mid, lo); /* swap it to beginning of array */
  765. /* We now wish to partition the array into three pieces, one
  766. consisiting of elements <= partition element, one of elements
  767. equal to the parition element, and one of element >= to it. This
  768. is done below; comments indicate conditions established at every
  769. step. */
  770. loguy = lo;
  771. higuy = hi + 1;
  772. /* Note that higuy decreases and loguy increases on every iteration,
  773. so loop must terminate. */
  774. for (;;) {
  775. /* lo <= loguy < hi, lo < higuy <= hi + 1,
  776. A[i] <= A[lo] for lo <= i <= loguy,
  777. A[i] >= A[lo] for higuy <= i <= hi */
  778. do {
  779. loguy ++;
  780. } while (loguy <= hi && compare_entries_sv(loguy, lo, s, bc, &error) <= 0);
  781. /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
  782. either loguy > hi or A[loguy] > A[lo] */
  783. do {
  784. higuy --;
  785. } while (higuy > lo && compare_entries_sv(higuy, lo, s, bc, &error) >= 0);
  786. /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
  787. either higuy <= lo or A[higuy] < A[lo] */
  788. if (higuy < loguy)
  789. break;
  790. /* if loguy > hi or higuy <= lo, then we would have exited, so
  791. A[loguy] > A[lo], A[higuy] < A[lo],
  792. loguy < hi, highy > lo */
  793. swap(loguy, higuy);
  794. /* Check admin and time limits here on the sort */
  795. if ( LDAP_SUCCESS != (return_value = sort_check(bc)) )
  796. {
  797. return return_value;
  798. }
  799. /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
  800. of loop is re-established */
  801. }
  802. /* A[i] >= A[lo] for higuy < i <= hi,
  803. A[i] <= A[lo] for lo <= i < loguy,
  804. higuy < loguy, lo <= higuy <= hi
  805. implying:
  806. A[i] >= A[lo] for loguy <= i <= hi,
  807. A[i] <= A[lo] for lo <= i <= higuy,
  808. A[i] = A[lo] for higuy < i < loguy */
  809. swap(lo, higuy); /* put partition element in place */
  810. /* OK, now we have the following:
  811. A[i] >= A[higuy] for loguy <= i <= hi,
  812. A[i] <= A[higuy] for lo <= i < higuy
  813. A[i] = A[lo] for higuy <= i < loguy */
  814. /* We've finished the partition, now we want to sort the subarrays
  815. [lo, higuy-1] and [loguy, hi].
  816. We do the smaller one first to minimize stack usage.
  817. We only sort arrays of length 2 or more.*/
  818. if ( higuy - 1 - lo >= hi - loguy ) {
  819. if (lo + 1 < higuy) {
  820. lostk[stkptr] = lo;
  821. histk[stkptr] = higuy - 1;
  822. ++stkptr;
  823. } /* save big recursion for later */
  824. if (loguy < hi) {
  825. lo = loguy;
  826. goto recurse; /* do small recursion */
  827. }
  828. }
  829. else {
  830. if (loguy < hi) {
  831. lostk[stkptr] = loguy;
  832. histk[stkptr] = hi;
  833. ++stkptr; /* save big recursion for later */
  834. }
  835. if (lo + 1 < higuy) {
  836. hi = higuy - 1;
  837. goto recurse; /* do small recursion */
  838. }
  839. }
  840. }
  841. /* We have sorted the array, except for any pending sorts on the stack.
  842. Check if there are any, and do them. */
  843. --stkptr;
  844. if (stkptr >= 0) {
  845. lo = lostk[stkptr];
  846. hi = histk[stkptr];
  847. goto recurse; /* pop subarray from stack */
  848. }
  849. else
  850. return LDAP_SUCCESS; /* all subarrays done */
  851. }
  852. /* End fix for bug # 394184 */
  853. static void shortsort (
  854. baggage_carrier *bc,
  855. ID *lo,
  856. ID *hi,
  857. sort_spec *s
  858. )
  859. {
  860. ID *p, *max;
  861. int error = 0;
  862. /* Note: in assertions below, i and j are alway inside original bound of
  863. array to sort. */
  864. while (hi > lo) {
  865. /* A[i] <= A[j] for i <= j, j > hi */
  866. max = lo;
  867. for (p = lo+1; p <= hi; p++) {
  868. /* A[i] <= A[max] for lo <= i < p */
  869. if (compare_entries_sv(p,max,s,bc,&error) > 0) {
  870. max = p;
  871. }
  872. /* A[i] <= A[max] for lo <= i <= p */
  873. }
  874. /* A[i] <= A[max] for lo <= i <= hi */
  875. swap(max, hi);
  876. /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
  877. hi--;
  878. /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
  879. }
  880. /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
  881. so array is sorted */
  882. }
  883. static void swap (ID *a,ID *b)
  884. {
  885. ID tmp;
  886. if ( a != b ) {
  887. tmp = *a;
  888. *a = *b;
  889. *b = tmp;
  890. }
  891. }