• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

leonchen83 / redis-replicator / #2153

06 Jun 2025 04:52AM UTC coverage: 71.352% (-0.3%) from 71.609%
#2153

push

chenby
redis 8.0

3 of 33 new or added lines in 14 files covered. (9.09%)

3 existing lines in 2 files now uncovered.

6630 of 9292 relevant lines covered (71.35%)

0.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.89
/src/main/java/com/moilioncircle/redis/replicator/rdb/RdbParser.java
1
/*
2
 * Copyright 2016-2018 Leon Chen
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.moilioncircle.redis.replicator.rdb;
18

19
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_AUX;
20
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_EOF;
21
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_EXPIRETIME;
22
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_EXPIRETIME_MS;
23
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_FREQ;
24
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_FUNCTION;
25
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_FUNCTION2;
26
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_IDLE;
27
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_MODULE_AUX;
28
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_RESIZEDB;
29
import static com.moilioncircle.redis.replicator.Constants.RDB_OPCODE_SELECTDB;
30
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_HASH;
31
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_HASH_LISTPACK;
32
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_HASH_LISTPACK_EX;
33
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_HASH_METADATA;
34
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_HASH_ZIPLIST;
35
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_HASH_ZIPMAP;
36
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_LIST;
37
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_LIST_QUICKLIST;
38
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_LIST_QUICKLIST_2;
39
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_LIST_ZIPLIST;
40
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_MODULE;
41
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_MODULE_2;
42
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_SET;
43
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_SET_INTSET;
44
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_SET_LISTPACK;
45
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_STREAM_LISTPACKS;
46
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_STREAM_LISTPACKS_2;
47
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_STREAM_LISTPACKS_3;
48
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_STRING;
49
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_ZSET;
50
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_ZSET_2;
51
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_ZSET_LISTPACK;
52
import static com.moilioncircle.redis.replicator.Constants.RDB_TYPE_ZSET_ZIPLIST;
53
import static com.moilioncircle.redis.replicator.Status.CONNECTED;
54
import static com.moilioncircle.redis.replicator.util.Tuples.of;
55

56
import java.io.IOException;
57

58
import org.slf4j.Logger;
59
import org.slf4j.LoggerFactory;
60

61
import com.moilioncircle.redis.replicator.AbstractReplicator;
62
import com.moilioncircle.redis.replicator.event.Event;
63
import com.moilioncircle.redis.replicator.event.PostRdbSyncEvent;
64
import com.moilioncircle.redis.replicator.event.PreRdbSyncEvent;
65
import com.moilioncircle.redis.replicator.io.RedisInputStream;
66
import com.moilioncircle.redis.replicator.rdb.datatype.ContextKeyValuePair;
67
import com.moilioncircle.redis.replicator.rdb.datatype.DB;
68

69
/**
70
 * Redis RDB format
71
 * <p>
72
 *
73
 * @author Leon Chen
74
 * @see <a href="https://github.com/antirez/redis/blob/3.0/src/rdb.c">rdb.c</a>
75
 * @see <a href="https://github.com/leonchen83/redis-replicator/wiki/RDB-dump-data-format">Redis rdb dump data format</a>
76
 * @since 2.1.0
77
 */
78
public class RdbParser {
79

80
    protected final RedisInputStream in;
81
    protected final RdbVisitor rdbVisitor;
82
    protected final AbstractReplicator replicator;
83
    protected static final Logger logger = LoggerFactory.getLogger(RdbParser.class);
1✔
84

85
    public RdbParser(RedisInputStream in, AbstractReplicator replicator) {
1✔
86
        this.in = in;
1✔
87
        this.replicator = replicator;
1✔
88
        this.rdbVisitor = this.replicator.getRdbVisitor();
1✔
89
    }
1✔
90

91
    /**
92
     * The RDB E-BNF
93
     * <p>
94
     * RDB        =    'REDIS', $version, [AUX], [MODULE_AUX], [FUNCTION], {SELECTDB, [RESIZEDB], {RECORD}}, '0xFF', [$checksum];
95
     * <p>
96
     * RECORD     =    [EXPIRED], [IDLE | FREQ], KEY, VALUE;
97
     * <p>
98
     * SELECTDB   =    '0xFE', $length;
99
     * <p>
100
     * AUX        =    {'0xFA', $string, $string};            (*Introduced in rdb version 7*)
101
     * <p>
102
     * MODULE_AUX =    {'0xF7', $module2};                    (*Introduced in rdb version 9*)
103
     * <p>
104
     * FUNCTION   =    {'0xF6', $function};                   (*Introduced in rdb version 10*)
105
     * <p>
106
     * RESIZEDB   =    '0xFB', $length, $length;              (*Introduced in rdb version 7*)
107
     * <p>
108
     * EXPIRED    =    ('0xFD', $second) | ('0xFC', $millisecond);
109
     * <p>
110
     * IDLE       =    {'0xF8', $value-type};                 (*Introduced in rdb version 9*)
111
     * <p>
112
     * FREQ       =    {'0xF9', $length};                     (*Introduced in rdb version 9*)
113
     * <p>
114
     * KEY        =    $string;
115
     * <p>
116
     * VALUE      =    $value-type, ( $string
117
     * <p>
118
     * | $list
119
     * <p>
120
     * | $set
121
     * <p>
122
     * | $setlistpack            (*Introduced in rdb version 11*)
123
     * <p>
124
     * | $zset
125
     * <p>
126
     * | $hash
127
     * <p>
128
     * | $zset2                  (*Introduced in rdb version 8*)
129
     * <p>
130
     * | $module                 (*Introduced in rdb version 8*)
131
     * <p>
132
     * | $module2                (*Introduced in rdb version 8*)
133
     * <p>
134
     * | $hashzipmap
135
     * <p>
136
     * | $listziplist
137
     * <p>
138
     * | $setintset
139
     * <p>
140
     * | $zsetziplist
141
     * <p>
142
     * | $hashziplist
143
     * <p>
144
     * | $listquicklist          (*Introduced in rdb version 7*)
145
     * <p>
146
     * | $streamlistpacks);      (*Introduced in rdb version 9*)
147
     * <p>
148
     * | $zsetlistpack);         (*Introduced in rdb version 10*)
149
     * <p>
150
     * | $hashlistpack);         (*Introduced in rdb version 10*)
151
     * <p>
152
     * | $listquicklist2);       (*Introduced in rdb version 10*)
153
     * <p>
154
     * | $streamlistpacks2);      (*Introduced in rdb version 10*)
155
     * <p>
156
     * | $streamlistpacks3);      (*Introduced in rdb version 11*)
157
     * <p>
158
     * | $hashlistpackex);      (*Introduced in rdb version 12*)
159
     * <p>
160
     * | $hashmetadata);      (*Introduced in rdb version 12*)
161
     * <p>
162
     * @return read bytes
163
     * @throws IOException when read timeout
164
     */
165
    public long parse() throws IOException {
166
        /*
167
         * ----------------------------
168
         * 52 45 44 49 53              # Magic String "REDIS"
169
         * 30 30 30 33                 # RDB Version Number in big endian. In this case, version = 0003 = 3
170
         * ----------------------------
171
         */
172
        long offset = 0L;
1✔
173
        boolean discard = this.replicator.getConfiguration().isDiscardRdbEvent();
1✔
174
        if (!discard) this.replicator.submitEvent(new PreRdbSyncEvent(), of(0L, 0L));
1✔
175
        in.mark();
1✔
176
        rdbVisitor.applyMagic(in);
1✔
177
        int version = rdbVisitor.applyVersion(in);
1✔
178
        offset += in.unmark();
1✔
179
        DB db = null;
1✔
180
        /*
181
         * rdb
182
         */
183
        loop:
184
        while (this.replicator.getStatus() == CONNECTED) {
1✔
185
            Event event = null;
1✔
186
            in.mark();
1✔
187
            int type = rdbVisitor.applyType(in);
1✔
188
            ContextKeyValuePair kv = new ContextKeyValuePair();
1✔
189
            kv.setDb(db);
1✔
190
            switch (type) {
1✔
191
                case RDB_OPCODE_EXPIRETIME:
192
                    event = rdbVisitor.applyExpireTime(in, version, kv);
×
193
                    break;
×
194
                case RDB_OPCODE_EXPIRETIME_MS:
195
                    event = rdbVisitor.applyExpireTimeMs(in, version, kv);
1✔
196
                    break;
1✔
197
                case RDB_OPCODE_FREQ:
198
                    event = rdbVisitor.applyFreq(in, version, kv);
1✔
199
                    break;
1✔
200
                case RDB_OPCODE_IDLE:
201
                    event = rdbVisitor.applyIdle(in, version, kv);
1✔
202
                    break;
1✔
203
                case RDB_OPCODE_AUX:
204
                    event = rdbVisitor.applyAux(in, version);
1✔
205
                    break;
1✔
206
                case RDB_OPCODE_MODULE_AUX:
207
                    event = rdbVisitor.applyModuleAux(in, version);
×
208
                    break;
×
209
                case RDB_OPCODE_FUNCTION:
210
                    event = rdbVisitor.applyFunction(in, version);
1✔
211
                    break;
1✔
212
                case RDB_OPCODE_FUNCTION2:
213
                    event = rdbVisitor.applyFunction2(in, version);
1✔
214
                    break;
1✔
215
                case RDB_OPCODE_RESIZEDB:
216
                    rdbVisitor.applyResizeDB(in, version, kv);
1✔
217
                    break;
1✔
218
                case RDB_OPCODE_SELECTDB:
219
                    db = rdbVisitor.applySelectDB(in, version);
1✔
220
                    break;
1✔
221
                case RDB_OPCODE_EOF:
222
                    long checksum = rdbVisitor.applyEof(in, version);
1✔
223
                    long start = offset;
1✔
224
                    offset += in.unmark();
1✔
225
                    if (!discard) this.replicator.submitEvent(new PostRdbSyncEvent(checksum), of(start, offset));
1✔
226
                    break loop;
227
                case RDB_TYPE_STRING:
228
                    event = rdbVisitor.applyString(in, version, kv);
1✔
229
                    break;
1✔
230
                case RDB_TYPE_LIST:
231
                    event = rdbVisitor.applyList(in, version, kv);
1✔
232
                    break;
1✔
233
                case RDB_TYPE_SET:
234
                    event = rdbVisitor.applySet(in, version, kv);
1✔
235
                    break;
1✔
236
                case RDB_TYPE_SET_LISTPACK:
237
                    event = rdbVisitor.applySetListPack(in, version, kv);
1✔
238
                    break;
1✔
239
                case RDB_TYPE_ZSET:
240
                    event = rdbVisitor.applyZSet(in, version, kv);
1✔
241
                    break;
1✔
242
                case RDB_TYPE_ZSET_2:
243
                    event = rdbVisitor.applyZSet2(in, version, kv);
1✔
244
                    break;
1✔
245
                case RDB_TYPE_HASH:
246
                    event = rdbVisitor.applyHash(in, version, kv);
1✔
247
                    break;
1✔
248
                case RDB_TYPE_HASH_ZIPMAP:
249
                    event = rdbVisitor.applyHashZipMap(in, version, kv);
1✔
250
                    break;
1✔
251
                case RDB_TYPE_LIST_ZIPLIST:
252
                    event = rdbVisitor.applyListZipList(in, version, kv);
1✔
253
                    break;
1✔
254
                case RDB_TYPE_SET_INTSET:
255
                    event = rdbVisitor.applySetIntSet(in, version, kv);
1✔
256
                    break;
1✔
257
                case RDB_TYPE_ZSET_ZIPLIST:
258
                    event = rdbVisitor.applyZSetZipList(in, version, kv);
1✔
259
                    break;
1✔
260
                case RDB_TYPE_ZSET_LISTPACK:
261
                    event = rdbVisitor.applyZSetListPack(in, version, kv);
1✔
262
                    break;
1✔
263
                case RDB_TYPE_HASH_ZIPLIST:
264
                    event = rdbVisitor.applyHashZipList(in, version, kv);
1✔
265
                    break;
1✔
266
                case RDB_TYPE_HASH_LISTPACK:
267
                    event = rdbVisitor.applyHashListPack(in, version, kv);
1✔
268
                    break;
1✔
269
                case RDB_TYPE_LIST_QUICKLIST:
270
                    event = rdbVisitor.applyListQuickList(in, version, kv);
1✔
271
                    break;
1✔
272
                case RDB_TYPE_LIST_QUICKLIST_2:
273
                    event = rdbVisitor.applyListQuickList2(in, version, kv);
1✔
274
                    break;
1✔
275
                case RDB_TYPE_MODULE:
276
                    event = rdbVisitor.applyModule(in, version, kv);
1✔
277
                    break;
1✔
278
                case RDB_TYPE_MODULE_2:
279
                    event = rdbVisitor.applyModule2(in, version, kv);
×
280
                    break;
×
281
                case RDB_TYPE_STREAM_LISTPACKS:
282
                    event = rdbVisitor.applyStreamListPacks(in, version, kv);
1✔
283
                    break;
1✔
284
                case RDB_TYPE_STREAM_LISTPACKS_2:
285
                    event = rdbVisitor.applyStreamListPacks2(in, version, kv);
1✔
286
                    break;
1✔
287
                case RDB_TYPE_STREAM_LISTPACKS_3:
288
                    event = rdbVisitor.applyStreamListPacks3(in, version, kv);
1✔
289
                    break;
1✔
290
                case RDB_TYPE_HASH_METADATA:
NEW
291
                    event = rdbVisitor.applyHashMetadata(in, version, kv);
×
NEW
292
                    break;
×
293
                case RDB_TYPE_HASH_LISTPACK_EX:
NEW
294
                    event = rdbVisitor.applyHashListPackEx(in, version, kv);
×
NEW
295
                    break;
×
296
                default:
297
                    throw new AssertionError("unexpected value type:" + type + ", check your ModuleParser or ValueIterableRdbVisitor.");
×
298
            }
299
            long start = offset;
1✔
300
            offset += in.unmark();
1✔
301
            if (event == null) continue;
1✔
302
            if (replicator.verbose() && logger.isDebugEnabled()) logger.debug("{}", event);
1✔
303
            if (!discard) this.replicator.submitEvent(event, of(start, offset));
1✔
304
        }
1✔
305
        return offset;
1✔
306
    }
307
}
308

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc