1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 #include "test.h"
40 
41 #include "loader/loader-internal.h"
42 #include "loader/pqueue.h"
43 
44 int found_dup = -1;
45 
46 // simple compare func
47 static int test_compare(DB * UU(db), const DBT *dbta, const DBT *dbtb)
48 {
49     int a = *((int*)dbta->data);
50     int b = *((int*)dbtb->data);
51     if ( a<b ) return -1;
52     if ( a>b ) return 1;
53     return 0;
54 }
55 
56 static inline DBT *dbt_init(DBT *dbt, void *data, uint32_t size) {
57     memset(dbt, 0, sizeof *dbt);
58     dbt->data = data;
59     dbt->size = size;
60     return dbt;
61 }
62 
63 static void err_cb(DB *db, int which_db, int err, DBT *key, DBT *val, void *extra) {
64     (void) db; (void) which_db; (void) err; (void) extra;
65     (void) val;
66     found_dup = *(int *)key->data;
67     if (verbose) printf("err_cb : key <%d> val <%d>\n", *(int *)key->data, *(int *)val->data);
68 }
69 
70 static int run_test(void)
71 {
72     const int n_sources=10;
73     pqueue_t      *pq;
74     pqueue_node_t *pq_nodes = (pqueue_node_t *) toku_malloc( n_sources * sizeof(pqueue_node_t));
75     pqueue_node_t *node;
76     DB *dest_db = NULL;
77     ft_compare_func compare = test_compare;
78     int r;
79     struct error_callback_s error_callback;
80     ft_loader_init_error_callback(&error_callback);
81     ft_loader_set_error_function(&error_callback, err_cb, NULL);
82 
83     r = pqueue_init(&pq, n_sources, 0, dest_db, compare, &error_callback);
84     if (r) return r;
85 
86     DBT keys[n_sources];
87     DBT vals[n_sources];
88     DBT zero;
89     toku_init_dbt_flags(&zero, DB_DBT_REALLOC);
90     int key_data[10] = {0, 4, 8, 9, 5, 1, 2, 6, 7, 3};
91 
92     for (int i=0;i<n_sources; i++) {
93         if (verbose) printf("%d ", key_data[i]);
94 	keys[i] = zero;
95 	vals[i] = zero;
96         dbt_init(&keys[i], &key_data[i], sizeof(int));
97     }
98     if (verbose) printf("\n");
99 
100     // test 1 : fill it up, then empty it out
101     for (int i=0; i<n_sources; i++) {
102         pq_nodes[i].key = &keys[i];
103         pq_nodes[i].val = &vals[i];
104         pq_nodes[i].i   = i;
105         pqueue_insert(pq, &pq_nodes[i]);
106     }
107 
108     for (int i=0; i<n_sources; i++) {
109         r = pqueue_pop(pq, &node);   assert(r==0);
110         if (verbose) printf("%d : %d\n", i, *(int*)(node->key->data));
111         if ( *(int*)(node->key->data) != i ) {
112             if (verbose)
113                 printf("FAIL\n");
114             return -1;
115         }
116     }
117     pqueue_free(pq);
118     if (verbose) printf("test1 : PASS\n");
119 
120     // test 2 : fill it, then empty and reload, then empty
121     {
122 	r = pqueue_init(&pq, n_sources, 0, dest_db, compare, &error_callback);
123 	if (r) return r;
124     }
125 
126     DBT more_keys[20];
127     DBT more_vals[20];
128     int more_key_data[20] = {0, 4, 8, 9, 5, 1, 2, 6, 7, 3, 10, 11, 14, 13, 12, 17, 19, 15, 18, 16};
129     for (int i=0; i<20; i++) {
130 	more_keys[i] = zero;
131 	more_vals[i] = zero;
132         dbt_init(&more_keys[i], &more_key_data[i], sizeof(int));
133     }
134 
135     for (int i=0; i<10; i++) {
136         pq_nodes[i].key = &more_keys[i];
137         pq_nodes[i].val = &more_vals[i];
138         pq_nodes[i].i   = i;
139         pqueue_insert(pq, &pq_nodes[i]);
140     }
141 
142     for (int i=0; i<5; i++) {
143         r = pqueue_pop(pq, &node);   assert(r==0);
144         if ( *(int *)node->key->data != i ) { printf("FAIL\n"); return -1; }
145         if (verbose) printf("%d : %d\n", i, *(int*)node->key->data);
146     }
147 
148     int n;
149     for (int i=5; i<15; i++) {
150         r = pqueue_pop(pq, &node);   assert(r==0);
151         if ( *(int *)node->key->data != i ) { printf("FAIL\n"); return -1; }
152         if (verbose) printf("%d : %d\n", i, *(int*)node->key->data);
153         n = node->i;
154         pq_nodes[n].key = &more_keys[i+5];
155         pq_nodes[n].val = &more_vals[i+5];
156         pqueue_insert(pq, &pq_nodes[n]);
157     }
158 
159     for (int i=15; i<20; i++) {
160         r = pqueue_pop(pq, &node);   assert(r==0);
161         if ( *(int*)node->key->data != i ) { printf("FAIL\n"); return -1; }
162         if (verbose) printf("%d : %d\n", i, *(int*)node->key->data);
163     }
164     if (verbose) printf("test2 : PASS\n");
165     pqueue_free(pq);
166 
167     // test 3 : put in a dup
168     {
169 	r = pqueue_init(&pq, 10, 0, dest_db, compare, &error_callback);
170 	if (r) return r;
171     }
172 
173     DBT keys3[10];
174     DBT vals3[10];
175     int key_data3[10] = {0, 1, 2, 3, 4, 5, 6, 6, 8, 9}; // dup is 6
176     int val_data3[10];
177 
178     for (int i=0; i<10; i++) {
179 	keys3[i] = zero;
180         vals3[i] = zero;
181         val_data3[i] = i;
182         dbt_init(&keys3[i], &key_data3[i], sizeof(int));
183         dbt_init(&vals3[i], &val_data3[i], sizeof(int));
184     }
185     int ii;
186     for (ii=0; ii<10; ii++) {
187         pq_nodes[ii].key = &keys3[ii];
188         pq_nodes[ii].val = &vals3[ii];
189         pq_nodes[ii].i   = ii;
190         r = pqueue_insert(pq, &pq_nodes[ii]);
191         if ( r != 0 ) goto found_duplicate6;
192     }
193     for (ii=0; ii<10; ii++) {
194         r = pqueue_pop(pq, &node);
195 //        if (verbose) printf("%d : %d\n", ii, *(int*)node->key->data);
196         if ( r != 0 ) goto found_duplicate6;
197     }
198 found_duplicate6:
199 //    if (verbose) printf("%d : %d\n", ii, *(int*)node->key->data);
200     if ( found_dup != 6 ) { printf("FAIL\n"); return -1; }
201     if (verbose) printf("test3 : PASS\n");
202     pqueue_free(pq);
203     ft_loader_destroy_error_callback(&error_callback);
204 
205     // test 4 - find duplicate when inserting
206     ft_loader_init_error_callback(&error_callback);
207     ft_loader_set_error_function(&error_callback, err_cb, NULL);
208     r = pqueue_init(&pq, 10, 0, dest_db, compare, &error_callback);        if (r) return r;
209 
210     found_dup = -1;
211     DBT keys4[10];
212     DBT vals4[10];
213     int key_data4[10] = {0, 0, 2, 3, 4, 5, 6, 7, 8, 9}; // dup is 0
214     int val_data4[10];
215 
216     for (int i=0; i<10; i++) {
217 	keys4[i] = zero;
218         vals4[i] = zero;
219         val_data4[i] = i;
220         dbt_init(&keys4[i], &key_data4[i], sizeof(int));
221         dbt_init(&vals4[i], &val_data4[i], sizeof(int));
222     }
223 
224     for (ii=0; ii<10; ii++) {
225         pq_nodes[ii].key = &keys4[ii];
226         pq_nodes[ii].val = &vals4[ii];
227         pq_nodes[ii].i   = ii;
228         r = pqueue_insert(pq, &pq_nodes[ii]);
229         if ( r != 0 ) {
230 //            if (verbose) printf("%d : %d\n", ii, *(int*)pq_nodes[ii].key->data);
231             goto found_duplicate0;
232         }
233     }
234     for (ii=0; ii<10; ii++) {
235         r = pqueue_pop(pq, &node);
236 //        if (verbose) printf("%d : %d\n", ii, *(int*)node->key->data);
237         if ( r != 0 ) goto found_duplicate0;
238     }
239 found_duplicate0:
240     if ( found_dup != 0 ) { printf("FAIL - found_dup : %d\n", found_dup); return -1; }
241     if (verbose) printf("test4 : PASS\n");
242     if (verbose) printf("PASS\n");
243     pqueue_free(pq);
244     toku_free(pq_nodes);
245     ft_loader_destroy_error_callback(&error_callback);
246 
247     return 0;
248 }
249 
250 
251 
252 int
253 test_main (int argc, const char *argv[]) {
254     argc--; argv++;
255     while (argc>0) {
256     	if (strcmp(argv[0], "-v")==0) {
257             verbose++;
258         }
259 	argc--;
260 	argv++;
261     }
262     return run_test();
263 }
264