]> mj.ucw.cz Git - libucw.git/blob - lib/sorter/s-fixint.h
de152b0a90422d5fae4bd56de7d4c1e9eb68a188
[libucw.git] / lib / sorter / s-fixint.h
1 /*
2  *      UCW Library -- Universal Sorter: Fixed-Size Internal Sorting Module
3  *
4  *      (c) 2007 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "lib/stkstring.h"
11
12 #define ASORT_PREFIX(x) SORT_PREFIX(array_##x)
13 #define ASORT_KEY_TYPE P(key)
14 #define ASORT_LT(x,y) (P(compare)(&(x), &(y)) < 0)
15 #ifdef SORT_INTERNAL_RADIX
16 #define ASORT_HASH(x) P(hash)(&(x))
17 #endif
18 #include "lib/sorter/array.h"
19
20 /*
21  *  This is a more efficient implementation of the internal sorter,
22  *  which runs under the following assumptions:
23  *
24  *     - the keys have fixed (and small) size
25  *     - no data are present after the key
26  *     - unification does not require any workspace
27  */
28
29 static size_t P(internal_workspace)(void)
30 {
31   size_t workspace = 0;
32 #ifdef SORT_UNIFY
33   workspace = sizeof(P(key) *);
34 #endif
35 #ifdef SORT_INTERNAL_RADIX
36   workspace = MAX(workspace, sizeof(P(key)));
37 #endif
38   return workspace;
39 }
40
41 static uns P(internal_num_keys)(struct sort_context *ctx)
42 {
43   size_t bufsize = ctx->big_buf_size;
44   size_t workspace = P(internal_workspace)();
45   if (workspace)
46     bufsize -= CPU_PAGE_SIZE;
47   u64 maxkeys = bufsize / (sizeof(P(key)) + workspace);
48   return MIN(maxkeys, ~0U);                                     // The number of records must fit in uns
49 }
50
51 static int P(internal)(struct sort_context *ctx, struct sort_bucket *bin, struct sort_bucket *bout, struct sort_bucket *bout_only)
52 {
53   sorter_alloc_buf(ctx);
54   struct fastbuf *in = sbuck_read(bin);
55   P(key) *buf = ctx->big_buf;
56   uns maxkeys = P(internal_num_keys)(ctx);
57
58   SORT_XTRACE(4, "s-fixint: Reading (maxkeys=%u, hash_bits=%d)", maxkeys, bin->hash_bits);
59   uns n = 0;
60   while (n < maxkeys && P(read_key)(in, &buf[n]))
61     n++;
62   if (!n)
63     return 0;
64   void *workspace UNUSED = ALIGN_PTR(&buf[n], CPU_PAGE_SIZE);
65
66   SORT_XTRACE(3, "s-fixint: Sorting %u items (%s items, %s workspace)",
67         n,
68         stk_fsize(n * sizeof(P(key))),
69         stk_fsize(n * P(internal_workspace)()));
70   timestamp_t timer;
71   init_timer(&timer);
72   buf = P(array_sort)(buf, n,
73 #ifdef SORT_INTERNAL_RADIX
74     workspace, bin->hash_bits
75 #else
76     NULL, 0
77 #endif
78     );
79   ctx->total_int_time += get_timer(&timer);
80
81   SORT_XTRACE(4, "s-fixint: Writing");
82   if (n < maxkeys)
83     bout = bout_only;
84   struct fastbuf *out = sbuck_write(bout);
85   bout->runs++;
86   uns merged UNUSED = 0;
87   for (uns i=0; i<n; i++)
88     {
89 #ifdef SORT_UNIFY
90       if (i < n-1 && !P(compare)(&buf[i], &buf[i+1]))
91         {
92           P(key) **keys = workspace;
93           uns n = 2;
94           keys[0] = &buf[i];
95           keys[1] = &buf[i+1];
96           while (!P(compare)(&buf[i], &buf[i+n]))
97             {
98               keys[n] = &buf[i+n];
99               n++;
100             }
101           P(write_merged)(out, keys, NULL, n, NULL);
102           merged += n - 1;
103           i += n - 1;
104           continue;
105         }
106 #endif
107 #ifdef SORT_ASSERT_UNIQUE
108       ASSERT(i == n-1 || P(compare)(&buf[i], &buf[i+1]) < 0);
109 #endif
110       P(write_key)(out, &buf[i]);
111     }
112 #ifdef SORT_UNIFY
113   SORT_XTRACE(3, "Merging reduced %d records", merged);
114 #endif
115
116   return (n == maxkeys);
117 }
118
119 static u64
120 P(internal_estimate)(struct sort_context *ctx, struct sort_bucket *b UNUSED)
121 {
122   return P(internal_num_keys)(ctx) * sizeof(P(key)) - 1;        // -1 since if the buffer is full, we don't recognize EOF
123 }