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 
7 #include "test_common.h"
8 #include "cutest.h"
9 
10 #define CHUNKSIZE (5 * 1000)  // > NCHUNKS for the bench purposes
11 #define NCHUNKS 10
12 
13 
14 typedef struct {
15   int32_t open;
16   int32_t close;
17   int32_t tell;
18   int32_t seek;
19   int32_t write;
20   int32_t read;
21   int32_t truncate;
22 } test_udio_params;
23 
24 
25 typedef struct {
26   blosc2_stdio_file *bfile;
27   test_udio_params *params;
28 } test_file;
29 
30 
test_open(const char * urlpath,const char * mode,void * params)31 void* test_open(const char *urlpath, const char *mode, void *params) {
32   test_file *my = malloc(sizeof(test_file));
33   my->params = params;
34   my->params->open++;
35 
36   my->bfile = blosc2_stdio_open(urlpath, mode, NULL);
37   return my;
38 }
39 
test_close(void * stream)40 int test_close(void *stream) {
41   test_file *my = (test_file *) stream;
42   my->params->close++;
43   int err =  blosc2_stdio_close(my->bfile);
44   free(my);
45   return err;
46 }
47 
test_tell(void * stream)48 int64_t test_tell(void *stream) {
49   test_file *my = (test_file *) stream;
50   my->params->tell++;
51   return blosc2_stdio_tell(my->bfile);
52 }
53 
test_seek(void * stream,int64_t offset,int whence)54 int test_seek(void *stream, int64_t offset, int whence) {
55   test_file *my = (test_file *) stream;
56   my->params->seek++;
57   return blosc2_stdio_seek(my->bfile, offset, whence);
58 }
59 
test_write(const void * ptr,int64_t size,int64_t nitems,void * stream)60 int64_t test_write(const void *ptr, int64_t size, int64_t nitems, void *stream) {
61   test_file *my = (test_file *) stream;
62   my->params->write++;
63   return blosc2_stdio_write(ptr, size, nitems, my->bfile);
64 }
65 
test_read(void * ptr,int64_t size,int64_t nitems,void * stream)66 int64_t test_read(void *ptr, int64_t size, int64_t nitems, void *stream) {
67   test_file *my = (test_file *) stream;
68   my->params->read++;
69   return blosc2_stdio_read(ptr, size, nitems, my->bfile);
70 }
71 
test_truncate(void * stream,int64_t size)72 int64_t test_truncate(void *stream, int64_t size) {
73   test_file *my = (test_file *) stream;
74   my->params->truncate++;
75   return blosc2_stdio_truncate(my->bfile, size);
76 }
77 
78 
79 typedef struct {
80   bool contiguous;
81   char *urlpath;
82 }test_udio_backend;
83 
CUTEST_TEST_DATA(udio)84 CUTEST_TEST_DATA(udio) {
85   blosc2_cparams cparams;
86 };
87 
CUTEST_TEST_SETUP(udio)88 CUTEST_TEST_SETUP(udio) {
89   blosc_init();
90 
91   blosc2_io_cb io_cb;
92 
93   io_cb.id = 244;
94   io_cb.open = (blosc2_open_cb) test_open;
95   io_cb.close = (blosc2_close_cb) test_close;
96   io_cb.read = (blosc2_read_cb) test_read;
97   io_cb.tell = (blosc2_tell_cb) test_tell;
98   io_cb.seek = (blosc2_seek_cb) test_seek;
99   io_cb.write = (blosc2_write_cb) test_write;
100   io_cb.truncate = (blosc2_truncate_cb) test_truncate;
101 
102   blosc2_register_io_cb(&io_cb);
103 
104   data->cparams = BLOSC2_CPARAMS_DEFAULTS;
105   data->cparams.typesize = sizeof(int32_t);
106   data->cparams.compcode = BLOSC_BLOSCLZ;
107   data->cparams.clevel = 4;
108   data->cparams.nthreads = 2;
109 
110   CUTEST_PARAMETRIZE(backend, test_udio_backend, CUTEST_DATA(
111       {true, "test_udio.b2frame"}, // disk - cframe
112       {false, "test_udio_s.b2frame"}, // disk - sframe
113   ));
114 }
115 
116 
CUTEST_TEST_TEST(udio)117 CUTEST_TEST_TEST(udio) {
118   CUTEST_GET_PARAMETER(backend, test_udio_backend);
119 
120   /* Free resources */
121   blosc2_remove_urlpath(backend.urlpath);
122 
123   int32_t nbytes = CHUNKSIZE * sizeof(int32_t);
124   int32_t *data_buffer = malloc(nbytes);
125   int32_t *rec_buffer = malloc(nbytes);
126 
127   /* Create a super-chunk container */
128   blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
129   cparams.typesize = sizeof(int32_t);
130   cparams.compcode = BLOSC_BLOSCLZ;
131   cparams.clevel = 9;
132   cparams.nthreads = 2;
133 
134   test_udio_params io_params = {0};
135   blosc2_io io = {.id = 244, .params = &io_params};
136   blosc2_storage storage = {.cparams=&cparams, .contiguous=backend.contiguous, .urlpath = backend.urlpath, .io=&io};
137 
138   blosc2_schunk *schunk = blosc2_schunk_new(&storage);
139 
140   for (int i = 0; i < NCHUNKS; ++i) {
141     int32_t cbytes = blosc2_schunk_append_buffer(schunk, data_buffer, nbytes);
142     CUTEST_ASSERT("Error during compression", cbytes >= 0);
143   }
144 
145   blosc2_schunk *schunk2 = blosc2_schunk_open_udio(backend.urlpath, &io);
146 
147   for (int i = 0; i < NCHUNKS; ++i) {
148     int32_t dbytes = blosc2_schunk_decompress_chunk(schunk2, i, rec_buffer, nbytes);
149     CUTEST_ASSERT("Error during decompression", dbytes >= 0);
150     for (int j = 0; j < CHUNKSIZE; ++j) {
151       CUTEST_ASSERT("Data are not equal", data_buffer[j] == rec_buffer[j]);
152     }
153   }
154 
155   // Check io params
156   CUTEST_ASSERT("Open must be positive", io_params.open > 0);
157   CUTEST_ASSERT("Close must be positive", io_params.close > 0);
158   CUTEST_ASSERT("Seek must be positive", io_params.seek > 0);
159   CUTEST_ASSERT("Write must be positive", io_params.write > 0);
160   CUTEST_ASSERT("Read must be positive", io_params.read > 0);
161   CUTEST_ASSERT("Truncate must be positive", io_params.truncate > 0);
162 
163   blosc2_schunk_free(schunk);
164   blosc2_schunk_free(schunk2);
165   free(data_buffer);
166   free(rec_buffer);
167 
168   return 0;
169 }
170 
CUTEST_TEST_TEARDOWN(udio)171 CUTEST_TEST_TEARDOWN(udio) {
172   blosc_destroy();
173 }
174 
175 
main()176 int main() {
177   CUTEST_TEST_RUN(udio)
178 }
179