1 /*
2   Copyright (C) 2021  The Blosc Developers <blosc@blosc.org>
3   https://blosc.org
4   License: BSD 3-Clause (see LICENSE.txt)
5 
6   See LICENSE.txt for details about copyright and rights to use.
7 */
8 
9 #include <stdio.h>
10 #include "test_common.h"
11 
12 #define CHUNKSIZE (200 * 1000)
13 #define BLOCKSIZE (20 * 1000)
14 #define NBLOCKS (CHUNKSIZE / BLOCKSIZE)
15 
16 /* Global vars */
17 int tests_run = 0;
18 int nchunks;
19 int clevel;
20 int16_t nthreads;
21 uint8_t filter;
22 
23 
test_lazy_chunk(void)24 static char* test_lazy_chunk(void) {
25   int32_t *data = malloc(CHUNKSIZE * sizeof(int32_t));
26     int32_t *data_dest = malloc(CHUNKSIZE * sizeof(int32_t));
27   int32_t isize = CHUNKSIZE * sizeof(int32_t);
28   int dsize;
29   int cbytes;
30   blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
31   cparams.filters[5] = filter;
32   blosc2_dparams dparams = BLOSC2_DPARAMS_DEFAULTS;
33   blosc2_schunk* schunk;
34 
35   /* Initialize the Blosc compressor */
36   blosc_init();
37 
38   /* Create a super-chunk container, backed by a frame */
39   cparams.typesize = sizeof(int32_t);
40   cparams.clevel = clevel;
41   cparams.nthreads = nthreads;
42   cparams.blocksize = BLOCKSIZE * cparams.typesize;
43   dparams.nthreads = nthreads;
44   char* urlpath = "test_lazy_chunk.b2frame";
45   remove(urlpath);
46   blosc2_storage storage = {.contiguous=true, .urlpath=urlpath, .cparams=&cparams, .dparams=&dparams};
47 
48   schunk = blosc2_schunk_new(&storage);
49 
50   // Feed it with data
51   for (int nchunk = 0; nchunk < nchunks; nchunk++) {
52     for (int i = 0; i < NBLOCKS; i++) {
53       for (int j = 0; j < BLOCKSIZE; j++) {
54         data[j + i * BLOCKSIZE] = j + i * BLOCKSIZE + nchunk * CHUNKSIZE;
55       }
56     }
57     int nchunks_ = blosc2_schunk_append_buffer(schunk, data, isize);
58     mu_assert("ERROR: bad append in frame", nchunks_ > 0);
59   }
60 
61   /* Gather some info */
62   if (nchunks > 0 && clevel > 0) {
63     mu_assert("ERROR: bad compression ratio in frame", schunk->nbytes > 10 * schunk->cbytes);
64   }
65 
66   // Check that blosc2_getitem_ctx works correctly with lazy chunks
67   bool needs_free;
68   uint8_t* lazy_chunk;
69   for (int nchunk = 0; nchunk < nchunks; nchunk++) {
70     cbytes = blosc2_schunk_get_lazychunk(schunk, nchunk, &lazy_chunk, &needs_free);
71     for (int i = 0; i < NBLOCKS - 1; i++) {
72       memset(data_dest, 0, isize);
73       dsize = blosc2_getitem_ctx(schunk->dctx, lazy_chunk, cbytes, i * BLOCKSIZE, BLOCKSIZE * 2, data_dest, isize);
74       mu_assert("ERROR: blosc2_getitem_ctx does not work correctly.", dsize >= 0);
75       for (int j = 0; j < BLOCKSIZE * 2; j++) {
76         mu_assert("ERROR: bad roundtrip (blosc2_getitem_ctx)",
77                   data_dest[j] == j + i * BLOCKSIZE + nchunk * CHUNKSIZE);
78       }
79     }
80     if (needs_free) {
81       free(lazy_chunk);
82     }
83   }
84 
85   // Check that lazy chunks can be decompressed correctly
86   for (int nchunk = 0; nchunk < nchunks; nchunk++) {
87     memset(data_dest, 0, isize);
88     cbytes = blosc2_schunk_get_lazychunk(schunk, nchunk, &lazy_chunk, &needs_free);
89     mu_assert("ERROR: cannot get lazy chunk.", cbytes > 0);
90     dsize = blosc2_decompress_ctx(schunk->dctx, lazy_chunk, cbytes, data_dest, isize);
91     if (needs_free) {
92       free(lazy_chunk);
93     }
94     mu_assert("ERROR: chunk cannot be decompressed correctly.", dsize >= 0);
95     for (int i = 0; i < NBLOCKS; i++) {
96       for (int j = 0; j < BLOCKSIZE; j++) {
97         mu_assert("ERROR: bad roundtrip (blosc2_decompress_ctx)",
98                   data_dest[j + i * BLOCKSIZE] == j + i * BLOCKSIZE + nchunk * CHUNKSIZE);
99       }
100     }
101   }
102 
103   /* Free resources */
104   blosc2_schunk_free(schunk);
105   /* Destroy the Blosc environment */
106   blosc_destroy();
107 
108   free(data);
109   free(data_dest);
110 
111   return EXIT_SUCCESS;
112 }
113 
all_tests(void)114 static char *all_tests(void) {
115   nchunks = 0;
116   clevel = 5;
117   nthreads = 1;
118   filter = BLOSC_SHUFFLE;
119   mu_run_test(test_lazy_chunk);
120 
121   nchunks = 1;
122   clevel = 5;
123   nthreads = 2;
124   filter = BLOSC_SHUFFLE;
125   mu_run_test(test_lazy_chunk);
126 
127   nchunks = 1;
128   clevel = 0;
129   nthreads = 2;
130   filter = BLOSC_BITSHUFFLE;
131   mu_run_test(test_lazy_chunk);
132 
133   nchunks = 10;
134   clevel = 5;
135   nthreads = 1;
136   filter = BLOSC_SHUFFLE;
137   mu_run_test(test_lazy_chunk);
138 
139   nchunks = 10;
140   clevel = 5;
141   nthreads = 2;
142   filter = BLOSC_BITSHUFFLE;
143   mu_run_test(test_lazy_chunk);
144 
145   nchunks = 10;
146   clevel = 0;
147   nthreads = 1;
148   filter = BLOSC_SHUFFLE;
149   mu_run_test(test_lazy_chunk);
150 
151   nchunks = 10;
152   clevel = 0;
153   nthreads = 2;
154   filter = BLOSC_BITSHUFFLE;
155   mu_run_test(test_lazy_chunk);
156 
157   return EXIT_SUCCESS;
158 }
159 
160 
main(void)161 int main(void) {
162   char *result;
163 
164   install_blosc_callback_test(); /* optionally install callback test */
165   blosc_init();
166 
167   /* Run all the suite */
168   result = all_tests();
169   if (result != EXIT_SUCCESS) {
170     printf(" (%s)\n", result);
171   }
172   else {
173     printf(" ALL TESTS PASSED");
174   }
175   printf("\tTests run: %d\n", tests_run);
176 
177   blosc_destroy();
178 
179   return result != EXIT_SUCCESS;
180 }
181