Line data Source code
1 : #include "fd_funk.h"
2 : #include <sys/types.h>
3 : #include <sys/stat.h>
4 : #include <fcntl.h>
5 : #include <string.h>
6 : #include <errno.h>
7 : #include <unistd.h>
8 : #include "../util/io/fd_io.h"
9 :
10 600 : #define FD_ARCH_MAGIC 0x92a1235fU
11 :
12 : int
13 : fd_funk_archive( fd_funk_t * funk,
14 300 : char const * filename ) {
15 300 : fd_wksp_t * wksp = fd_funk_wksp( funk );
16 300 : fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
17 300 : fd_funk_partvec_t * partvec = fd_funk_get_partvec( funk, wksp );
18 :
19 300 : FD_LOG_NOTICE(( "writing %s ...", filename ));
20 :
21 300 : int fd = open( filename, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
22 300 : if( fd == -1 ) {
23 0 : FD_LOG_WARNING(( "failed to open %s: %s", filename, strerror(errno) ));
24 0 : return FD_FUNK_ERR_SYS;
25 0 : }
26 :
27 300 : fd_io_buffered_ostream_t str;
28 300 : uchar wbuf[1<<17];
29 300 : fd_io_buffered_ostream_init( &str, fd, wbuf, sizeof(wbuf) );
30 300 : ulong tot = 0;
31 :
32 300 : #define ARCH_WRITE(buf, sz) \
33 35562 : do { \
34 35562 : int err = fd_io_buffered_ostream_write( &str, buf, sz); \
35 35562 : if( err ) { \
36 0 : FD_LOG_WARNING(( "failed to write %s: %s", filename, fd_io_strerror(err) )); \
37 0 : close( fd ); \
38 0 : unlink( filename ); \
39 0 : return FD_FUNK_ERR_SYS; \
40 0 : } \
41 35562 : tot += sz; \
42 35562 : } while(0)
43 :
44 300 : uint magic = FD_ARCH_MAGIC;
45 300 : ARCH_WRITE( &magic, sizeof(magic) );
46 300 : ARCH_WRITE( &partvec->num_part, sizeof(partvec->num_part) );
47 :
48 300 : for( fd_funk_rec_map_iter_t iter = fd_funk_rec_map_iter_init( rec_map );
49 7395 : !fd_funk_rec_map_iter_done( rec_map, iter );
50 7095 : iter = fd_funk_rec_map_iter_next( rec_map, iter ) ) {
51 7095 : fd_funk_rec_t * rec = fd_funk_rec_map_iter_ele( rec_map, iter );
52 7095 : ulong txn_idx = fd_funk_txn_idx( rec->txn_cidx );
53 7095 : if( fd_funk_txn_idx_is_null( txn_idx ) ) { /* This is a record from the last published transaction */
54 7095 : uchar type = (uchar)0xa5;
55 7095 : ARCH_WRITE( &type, sizeof(type) );
56 7095 : ARCH_WRITE( rec->pair.key, sizeof(rec->pair.key) );
57 7095 : ARCH_WRITE( &rec->part, sizeof(rec->part) );
58 7095 : ARCH_WRITE( &rec->val_sz, sizeof(rec->val_sz) );
59 7095 : if( rec->val_sz ) {
60 6282 : ARCH_WRITE( fd_wksp_laddr_fast( wksp, rec->val_gaddr ), rec->val_sz );
61 6282 : }
62 7095 : }
63 7095 : }
64 :
65 300 : uchar type = (uchar)0x5a;
66 300 : ARCH_WRITE( &type, sizeof(type) );
67 :
68 300 : int err = fd_io_buffered_ostream_flush( &str );
69 300 : if( err ) {
70 0 : FD_LOG_WARNING(( "failed to write %s: %s", filename, fd_io_strerror(err) ));
71 0 : close( fd );
72 0 : unlink( filename );
73 0 : return FD_FUNK_ERR_SYS;
74 0 : }
75 300 : close( fd );
76 :
77 300 : FD_LOG_NOTICE(( "wrote %lu bytes to %s", tot, filename ));
78 :
79 300 : return FD_FUNK_SUCCESS;
80 300 : }
81 :
82 : int
83 : fd_funk_unarchive( fd_funk_t * funk,
84 300 : char const * filename ) {
85 300 : fd_wksp_t * wksp = fd_funk_wksp( funk );
86 300 : fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
87 300 : ulong rec_max = funk->rec_max;
88 300 : fd_alloc_t * alloc = fd_funk_alloc( funk, wksp );
89 :
90 300 : FD_LOG_NOTICE(( "reading %s ...", filename ));
91 :
92 300 : int fd = open( filename, O_RDONLY );
93 300 : if( fd == -1 ) {
94 0 : FD_LOG_WARNING(( "failed to open %s: %s", filename, strerror(errno) ));
95 0 : return FD_FUNK_ERR_SYS;
96 0 : }
97 :
98 300 : fd_io_buffered_istream_t str;
99 300 : uchar rbuf[1<<17];
100 300 : fd_io_buffered_istream_init( &str, fd, rbuf, sizeof(rbuf) );
101 300 : ulong tot = 0;
102 :
103 300 : #define ARCH_READ(buf, sz) \
104 35562 : do { \
105 35562 : int err = fd_io_buffered_istream_read( &str, buf, sz); \
106 35562 : if( err ) { \
107 0 : FD_LOG_WARNING(( "failed to read %s: %s", filename, fd_io_strerror(err) )); \
108 0 : close( fd ); \
109 0 : return FD_FUNK_ERR_SYS; \
110 0 : } \
111 35562 : tot += sz; \
112 35562 : } while(0)
113 :
114 300 : uint magic;
115 300 : ARCH_READ( &magic, sizeof(magic) );
116 300 : if( magic != FD_ARCH_MAGIC ) {
117 0 : FD_LOG_WARNING(( "archive %s has wrong magic number", filename ));
118 0 : close( fd );
119 0 : return FD_FUNK_ERR_SYS;
120 0 : }
121 300 : uint num_part;
122 300 : ARCH_READ( &num_part, sizeof(num_part) );
123 300 : fd_funk_set_num_partitions( funk, num_part );
124 300 : fd_funk_partvec_t * partvec = fd_funk_get_partvec( funk, wksp );
125 :
126 300 : uchar type;
127 300 : fd_funk_xid_key_pair_t pair;
128 300 : fd_memset( &pair, 0, sizeof(pair) );
129 300 : uint part;
130 300 : uint val_sz;
131 :
132 7395 : for(;;) {
133 7395 : ARCH_READ( &type, sizeof(type) );
134 7395 : if( type == (uchar)0x5a ) break;
135 7095 : switch( type ) {
136 :
137 7095 : case (uchar)0xa5: {
138 7095 : ARCH_READ( pair.key, sizeof(pair.key) );
139 7095 : ARCH_READ( &part, sizeof(part) );
140 7095 : ARCH_READ( &val_sz, sizeof(val_sz) );
141 :
142 7095 : if( FD_UNLIKELY( fd_funk_rec_map_is_full( rec_map ) ) ) {
143 0 : FD_LOG_WARNING(( "archive %s has too many records to fit in given funk", filename ));
144 0 : close( fd );
145 0 : return FD_FUNK_ERR_MEM;
146 0 : }
147 :
148 7095 : fd_funk_rec_t * rec = fd_funk_rec_map_insert( rec_map, &pair );
149 7095 : ulong rec_idx = (ulong)(rec - rec_map);
150 7095 : if( FD_UNLIKELY( rec_idx>=rec_max ) ) FD_LOG_CRIT(( "memory corruption detected (bad idx)" ));
151 :
152 7095 : ulong rec_prev_idx = funk->rec_tail_idx;
153 :
154 7095 : rec->prev_idx = rec_prev_idx;
155 7095 : rec->next_idx = FD_FUNK_REC_IDX_NULL;
156 7095 : rec->txn_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
157 7095 : rec->tag = 0U;
158 7095 : rec->flags = 0UL;
159 :
160 7095 : int first_born = fd_funk_rec_idx_is_null( rec_prev_idx );
161 7095 : if( first_born ) funk->rec_head_idx = rec_idx;
162 6795 : else rec_map[ rec_prev_idx ].next_idx = rec_idx;
163 :
164 7095 : funk->rec_tail_idx = rec_idx;
165 :
166 7095 : fd_funk_val_init( rec );
167 7095 : if( val_sz ) {
168 6282 : int err;
169 6282 : if( !fd_funk_val_truncate( rec, val_sz, alloc, wksp, &err ) ) {
170 0 : FD_LOG_WARNING(( "archive %s has too much data to fit in given funk wksp", filename ));
171 0 : close( fd );
172 0 : return err;
173 0 : }
174 6282 : ARCH_READ( fd_wksp_laddr_fast( wksp, rec->val_gaddr ), val_sz );
175 6282 : }
176 :
177 7095 : fd_funk_part_init( rec );
178 7095 : if( part != FD_FUNK_PART_NULL ) {
179 5034 : fd_funk_part_set_intern( partvec, rec_map, rec, part );
180 5034 : }
181 7095 : break;
182 7095 : }
183 :
184 0 : default:
185 0 : FD_LOG_WARNING(( "archive %s has unknown record type", filename ));
186 0 : close( fd );
187 0 : return FD_FUNK_ERR_SYS;
188 7095 : }
189 7095 : }
190 :
191 300 : close( fd );
192 :
193 300 : FD_LOG_NOTICE(( "read %lu bytes from %s", tot, filename ));
194 :
195 300 : return FD_FUNK_SUCCESS;
196 300 : }
|