geoff 2004/02/16 11:58:18
Modified: . Changes
src/modules/perl modperl_apache_compat.c
t/response/TestAPR table.pm
Log:
copy apr_table_compress logic from later httpd versions in case mod_perl
is built against 2.0.46, as mod_perl now requires it internally.
Revision Changes Path
1.331 +5 -0 modperl-2.0/Changes
Index: Changes
===================================================================
RCS file: /home/cvs/modperl-2.0/Changes,v
retrieving revision 1.330
retrieving revision 1.331
diff -u -r1.330 -r1.331
--- Changes 14 Feb 2004 01:38:05 -0000 1.330
+++ Changes 16 Feb 2004 19:58:18 -0000 1.331
@@ -12,6 +12,11 @@
=item 1.99_13-dev
+copy apr_table_compress logic from later httpd versions in case mod_perl
+is built against 2.0.46, as mod_perl now requires it internally. users
+should be aware that 2.0.47 may become the oldest supported httpd version
+in the near future. [Geoffrey Young]
+
Fix the corruption of the httpd process argv[0], caused by $0
manipulating [Stas]
1.4 +217 -2 modperl-2.0/src/modules/perl/modperl_apache_compat.c
Index: modperl_apache_compat.c
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_apache_compat.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- modperl_apache_compat.c 22 Aug 2003 19:15:09 -0000 1.3
+++ modperl_apache_compat.c 16 Feb 2004 19:58:18 -0000 1.4
@@ -10,10 +10,225 @@
which is major mmn 20020903, minor mmn 4 */
#if ! AP_MODULE_MAGIC_AT_LEAST(20020903,4)
-/* added in APACHE_2_0_47/APR_0_9_4 */
+/* added in APACHE_2_0_47/APR_0_9_4 - duplicated here for 2.0.46.
+ * I'd rather not duplicate it, but we use apr_table_compress
+ * in the directive merge routines, so it's either duplicate it
+ * here, recode the compress logic there, or drop 2.0.46 support
+ */
+
+#define TABLE_HASH_SIZE 32
+
+struct apr_table_t {
+ apr_array_header_t a;
+#ifdef MAKE_TABLE_PROFILE
+ /** Who created the array. */
+ void *creator;
+#endif
+ apr_uint32_t index_initialized;
+ int index_first[TABLE_HASH_SIZE];
+ int index_last[TABLE_HASH_SIZE];
+};
+
+static apr_table_entry_t **table_mergesort(apr_pool_t *pool,
+ apr_table_entry_t **values, int n)
+{
+ /* Bottom-up mergesort, based on design in Sedgewick's "Algorithms
+ * in C," chapter 8
+ */
+ apr_table_entry_t **values_tmp =
+ (apr_table_entry_t **)apr_palloc(pool, n * sizeof(apr_table_entry_t*));
+ int i;
+ int blocksize;
+
+ /* First pass: sort pairs of elements (blocksize=1) */
+ for (i = 0; i + 1 < n; i += 2) {
+ if (strcasecmp(values[i]->key, values[i + 1]->key) > 0) {
+ apr_table_entry_t *swap = values[i];
+ values[i] = values[i + 1];
+ values[i + 1] = swap;
+ }
+ }
+
+ /* Merge successively larger blocks */
+ blocksize = 2;
+ while (blocksize < n) {
+ apr_table_entry_t **dst = values_tmp;
+ int next_start;
+ apr_table_entry_t **swap;
+
+ /* Merge consecutive pairs blocks of the next blocksize.
+ * Within a block, elements are in sorted order due to
+ * the previous iteration.
+ */
+ for (next_start = 0; next_start + blocksize < n;
+ next_start += (blocksize + blocksize)) {
+
+ int block1_start = next_start;
+ int block2_start = block1_start + blocksize;
+ int block1_end = block2_start;
+ int block2_end = block2_start + blocksize;
+ if (block2_end > n) {
+ /* The last block may be smaller than blocksize */
+ block2_end = n;
+ }
+ for (;;) {
+
+ /* Merge the next two blocks:
+ * Pick the smaller of the next element from
+ * block 1 and the next element from block 2.
+ * Once either of the blocks is emptied, copy
+ * over all the remaining elements from the
+ * other block
+ */
+ if (block1_start == block1_end) {
+ for (; block2_start < block2_end; block2_start++) {
+ *dst++ = values[block2_start];
+ }
+ break;
+ }
+ else if (block2_start == block2_end) {
+ for (; block1_start < block1_end; block1_start++) {
+ *dst++ = values[block1_start];
+ }
+ break;
+ }
+ if (strcasecmp(values[block1_start]->key,
+ values[block2_start]->key) > 0) {
+ *dst++ = values[block2_start++];
+ }
+ else {
+ *dst++ = values[block1_start++];
+ }
+ }
+ }
+
+ /* If n is not a multiple of 2*blocksize, some elements
+ * will be left over at the end of the array.
+ */
+ for (i = dst - values_tmp; i < n; i++) {
+ values_tmp[i] = values[i];
+ }
+
+ /* The output array of this pass becomes the input
+ * array of the next pass, and vice versa
+ */
+ swap = values_tmp;
+ values_tmp = values;
+ values = swap;
+
+ blocksize += blocksize;
+ }
+
+ return values;
+}
void apr_table_compress(apr_table_t *t, unsigned flags)
{
- modperl_apr_func_not_implemented(apr_table_compress, 2.0.47, 0.9.4);
+ apr_table_entry_t **sort_array;
+ apr_table_entry_t **sort_next;
+ apr_table_entry_t **sort_end;
+ apr_table_entry_t *table_next;
+ apr_table_entry_t **last;
+ int i;
+ int dups_found;
+
+ if (t->a.nelts <= 1) {
+ return;
+ }
+
+ /* Copy pointers to all the table elements into an
+ * array and sort to allow for easy detection of
+ * duplicate keys
+ */
+ sort_array = (apr_table_entry_t **)
+ apr_palloc(t->a.pool, t->a.nelts * sizeof(apr_table_entry_t*));
+ sort_next = sort_array;
+ table_next = (apr_table_entry_t *)t->a.elts;
+ i = t->a.nelts;
+ do {
+ *sort_next++ = table_next++;
+ } while (--i);
+
+ /* Note: the merge is done with mergesort instead of quicksort
+ * because mergesort is a stable sort and runs in n*log(n)
+ * time regardless of its inputs (quicksort is quadratic in
+ * the worst case)
+ */
+ sort_array = table_mergesort(t->a.pool, sort_array, t->a.nelts);
+
+ /* Process any duplicate keys */
+ dups_found = 0;
+ sort_next = sort_array;
+ sort_end = sort_array + t->a.nelts;
+ last = sort_next++;
+ while (sort_next < sort_end) {
+ if (((*sort_next)->key_checksum == (*last)->key_checksum) &&
+ !strcasecmp((*sort_next)->key, (*last)->key)) {
+ apr_table_entry_t **dup_last = sort_next + 1;
+ dups_found = 1;
+ while ((dup_last < sort_end) &&
+ ((*dup_last)->key_checksum == (*last)->key_checksum) &&
+ !strcasecmp((*dup_last)->key, (*last)->key)) {
+ dup_last++;
+ }
+ dup_last--; /* Elements from last through dup_last, inclusive,
+ * all have the same key
+ */
+ if (flags == APR_OVERLAP_TABLES_MERGE) {
+ apr_size_t len = 0;
+ apr_table_entry_t **next = last;
+ char *new_val;
+ char *val_dst;
+ do {
+ len += strlen((*next)->val);
+ len += 2; /* for ", " or trailing null */
+ } while (++next <= dup_last);
+ new_val = (char *)apr_palloc(t->a.pool, len);
+ val_dst = new_val;
+ next = last;
+ for (;;) {
+ strcpy(val_dst, (*next)->val);
+ val_dst += strlen((*next)->val);
+ next++;
+ if (next > dup_last) {
+ *val_dst = 0;
+ break;
+ }
+ else {
+ *val_dst++ = ',';
+ *val_dst++ = ' ';
+ }
+ }
+ (*last)->val = new_val;
+ }
+ else { /* overwrite */
+ (*last)->val = (*dup_last)->val;
+ }
+ do {
+ (*sort_next)->key = NULL;
+ } while (++sort_next <= dup_last);
+ }
+ else {
+ last = sort_next++;
+ }
+ }
+
+ /* Shift elements to the left to fill holes left by removing duplicates */
+ if (dups_found) {
+ apr_table_entry_t *src = (apr_table_entry_t *)t->a.elts;
+ apr_table_entry_t *dst = (apr_table_entry_t *)t->a.elts;
+ apr_table_entry_t *last_elt = src + t->a.nelts;
+ do {
+ if (src->key) {
+ *dst++ = *src;
+ }
+ } while (++src < last_elt);
+ t->a.nelts -= (last_elt - dst);
+ }
+
+ /* XXX mod_perl: remove to avoid more code duplication.
+ * XXX makes us slower on 2.0.46
+ */
+ /* table_reindex(t); */
}
#endif /* pre-APR_0_9_5 (APACHE_2_0_47) */
1.13 +10 -16 modperl-2.0/t/response/TestAPR/table.pm
Index: table.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/t/response/TestAPR/table.pm,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- table.pm 25 Nov 2003 20:31:29 -0000 1.12
+++ table.pm 16 Feb 2004 19:58:18 -0000 1.13
@@ -14,13 +14,10 @@
my $filter_count;
my $TABLE_SIZE = 20;
-use constant HAVE_APACHE_2_0_47 => have_min_apache_version('2.0.47');
-
sub handler {
my $r = shift;
- my $tests = 21;
- $tests += 2 if HAVE_APACHE_2_0_47;
+ my $tests = 23;
plan $r, tests => $tests;
@@ -133,18 +130,15 @@
ok @foo == 3;
ok $bar[0] eq 'beer';
- # BACK_COMPAT_MARKER: make back compat issues easy to find :)
- if (HAVE_APACHE_2_0_47) {
- $overlay->compress(APR::OVERLAP_TABLES_MERGE);
-
- # $add first, then $base
- ok t_cmp($overlay->get('foo'),
- 'three, one, two',
- "\$overlay->compress");
- ok t_cmp($overlay->get('bar'),
- 'beer',
- "\$overlay->compress");
- }
+ $overlay->compress(APR::OVERLAP_TABLES_MERGE);
+
+ # $add first, then $base
+ ok t_cmp($overlay->get('foo'),
+ 'three, one, two',
+ "\$overlay->compress");
+ ok t_cmp($overlay->get('bar'),
+ 'beer',
+ "\$overlay->compress");
Apache::OK;
}