forked from redis/redis
-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathctrip_swap.h
More file actions
2905 lines (2461 loc) · 103 KB
/
ctrip_swap.h
File metadata and controls
2905 lines (2461 loc) · 103 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef __CTRIP_SWAP_H__
#define __CTRIP_SWAP_H__
/* Copyright (c) 2021, ctrip.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "server.h"
#include <rocksdb/c.h>
#include "atomicvar.h"
#include "ctrip_lru_cache.h"
#include "ctrip_cuckoo_filter.h"
#include "ctrip_swap_adlist.h"
#include "ctrip_wtdigest.h"
void dbSetValue(redisDb* db, robj* key, robj **valref, dictEntryLink link,
int overwrite, int updateKeySizes, int keepTTL);
#define IN /* Input parameter */
#define OUT /* Output parameter */
#define INOUT /* Input/Output parameter */
#define MOVE /* Moved ownership */
#define DATA_CF 0
#define META_CF 1
#define SCORE_CF 2
#define CF_COUNT 3
#define data_cf_name "default"
#define meta_cf_name "meta"
#define score_cf_name "score"
extern const char *swap_cf_names[CF_COUNT];
#define rocksdb_stats_section "rocksdb.stats"
#define rocksdb_stats_section_len 13
/* --- cmd intention flags --- */
/* Delete key in rocksdb when swap in. */
#define SWAP_IN_DEL (1U<<0)
/* Only need to swap meta for hash/set/zset/list/bitmap */
#define SWAP_IN_META (1U<<1)
/* Delete key in rocksdb and mock value needed to be swapped in. */
#define SWAP_IN_DEL_MOCK_VALUE (1U<<2)
/* Data swap in will be overwritten by fun dbOverwrite
* same as SWAP_IN_DEL for collection type(SET, ZSET, LISH, HASH...), same as SWAP_IN for STRING */
#define SWAP_IN_OVERWRITE (1U<<3)
/* When swap finished, meta will be deleted(so that key will turn pure hot).*/
#define SWAP_IN_FORCE_HOT (1U<<4)
/* whether to expire Keys with generated in writtable slave is decided
* before submitExpireClientRequest and should not skip expire even
* if current role is slave. */
#define SWAP_EXPIRE_FORCE (1U<<5)
/* If oom would happen during RIO, swap will abort. */
#define SWAP_OOM_CHECK (1U<<6)
/* This is a metascan request for scan command. */
#define SWAP_METASCAN_SCAN (1U<<7)
/* This is a metascan request for randomkey command. */
#define SWAP_METASCAN_RANDOMKEY (1U<<8)
/* This is a metascan request for active-expire. */
#define SWAP_METASCAN_EXPIRE (1U<<9)
/* This is a persist requset. */
#define SWAP_OUT_PERSIST (1U<<10)
/* Keep data in memory because memory is sufficient. */
#define SWAP_OUT_KEEP_DATA (1U<<11)
/* --- swap intention flags --- */
/* Delete rocksdb data key when swap in */
#define SWAP_EXEC_IN_DEL (1U<<0)
/* object meta will be deleted from db.meta */
#define SWAP_EXEC_FORCE_HOT (1U<<1)
/* check whether oom would happend during RIO */
#define SWAP_EXEC_OOM_CHECK (1U<<2)
/* Don't delete key in keyspace when swap (Delete key in rocksdb) finish. */
#define SWAP_FIN_DEL_SKIP (1U<<3)
/* Reserve data when swap out. */
#define SWAP_EXEC_OUT_KEEP_DATA (1U<<4)
#define SWAP_UNSET -1
#define SWAP_NOP 0
#define SWAP_IN 1
#define SWAP_OUT 2
#define SWAP_DEL 3
#define SWAP_UTILS 4
#define SWAP_TYPES 5
/* next of OBJ_STREAM */
#define OBJ_BITMAP 7
#define SWAP_TYPE_STRING OBJ_STRING
#define SWAP_TYPE_LIST OBJ_LIST
#define SWAP_TYPE_SET OBJ_SET
#define SWAP_TYPE_ZSET OBJ_ZSET
#define SWAP_TYPE_HASH OBJ_HASH
#define SWAP_TYPE_STREAM OBJ_STREAM
#define SWAP_TYPE_BITMAP OBJ_BITMAP
static inline const char *swapIntentionName(int intention) {
const char *name = "?";
const char *intentions[] = {"NOP", "IN", "OUT", "DEL", "UTILS"};
if (intention >= 0 && intention < SWAP_TYPES)
name = intentions[intention];
return name;
}
static inline int getSwapIntentionByName(char *name) {
const char *intentions[] = {"NOP", "IN", "OUT", "DEL", "UTILS"};
for (int intention = 0; intention < SWAP_TYPES; intention++) {
if (!strcasecmp(intentions[intention], name)) {
return intention;
}
}
return SWAP_UNSET;
}
static inline int isMetaScanRequest(uint32_t intention_flag) {
return (intention_flag & SWAP_METASCAN_SCAN) ||
(intention_flag & SWAP_METASCAN_RANDOMKEY) ||
(intention_flag & SWAP_METASCAN_EXPIRE);
}
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) < (b) ? (b) : (a))
/* Cmd */
#define REQUEST_LEVEL_SVR 0
#define REQUEST_LEVEL_DB 1
#define REQUEST_LEVEL_KEY 2
#define REQUEST_LEVEL_TYPES 3
#define MAX_KEYREQUESTS_BUFFER 8
#define SWAP_CMD_COUNT 239
// extern struct redisCommand redisCommandTable[SWAP_CMD_COUNT];
typedef struct swapCmdTrace swapCmdTrace;
typedef struct swapTrace swapTrace;
typedef void (*freefunc)(void *);
static inline const char *requestLevelName(int level) {
const char *name = "?";
const char *levels[] = {"SVR","DB","KEY"};
if (level >= 0 && level < REQUEST_LEVEL_TYPES)
name = levels[level];
return name;
}
#define SEGMENT_TYPE_HOT 0
#define SEGMENT_TYPE_COLD 1
#define SEGMENT_TYPE_BOTH 2
/* Both start and end are inclusive, see addListRangeReply for details. */
typedef struct range {
long long start;
long long end;
int reverse; /* LTRIM command specifies range to keep, so swap in the reverse range */
} range;
#define KEYREQUEST_TYPE_KEY 0
#define KEYREQUEST_TYPE_SUBKEY 1
#define KEYREQUEST_TYPE_RANGE 2
#define KEYREQUEST_TYPE_SCORE 3
#define KEYREQUEST_TYPE_SAMPLE 4
#define KEYREQUEST_TYPE_BTIMAP_OFFSET 5
#define KEYREQUEST_TYPE_BTIMAP_RANGE 6
typedef struct argRewriteRequest {
int mstate_idx; /* >=0 if current command is a exec, means index in mstate; -1 means req not in multi/exec */
int arg_idx; /* index of argument to use for rewrite func */
} argRewriteRequest;
static inline void argRewriteRequestInit(argRewriteRequest *arg_req) {
arg_req->mstate_idx = -1;
arg_req->arg_idx = -1;
}
typedef struct keyRequest{
int dbid;
int level;
int cmd_intention;
int cmd_intention_flags;
uint64_t cmd_flags;
int type; /* request type */
int deferred;
robj *key;
union {
struct {
int num_subkeys;
robj **subkeys;
} b; /* subkey: hash, set */
struct {
int num_ranges;
range *ranges;
} l; /* range: list */
struct {
zrangespec* rangespec;
int reverse;
int limit;
} zs; /* zset score*/
struct {
int count;
} sp; /* sample */
struct {
long long offset;
} bo; /* bitmap offset*/
struct {
long long start;
long long end;
} br; /* bitmap range*/
};
argRewriteRequest arg_rewrite[2];
swapCmdTrace *swap_cmd;
swapTrace *trace;
} keyRequest;
void copyKeyRequest(keyRequest *dst, keyRequest *src);
void moveKeyRequest(keyRequest *dst, keyRequest *src);
void keyRequestDeinit(keyRequest *key_request);
void getKeyRequests(client *c, struct getKeyRequestsResult *result);
void releaseKeyRequests(struct getKeyRequestsResult *result);
int getKeyRequestsNone(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGlobal(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsMetaScan(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsSort(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define getKeyRequestsHsetnx getKeyRequestsHset
#define getKeyRequestsHget getKeyRequestsHmget
#define getKeyRequestsHdel getKeyRequestsHmget
#define getKeyRequestsHstrlen getKeyRequestsHmget
#define getKeyRequestsHincrby getKeyRequestsHget
#define getKeyRequestsHincrbyfloat getKeyRequestsHmget
#define getKeyRequestsHexists getKeyRequestsHmget
#define getKeyRequestsHgetdel getKeyRequestsHmget
int getKeyRequestsHset(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsHmget(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsHlen(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define getKeyRequestsSadd getKeyRequestSmembers
#define getKeyRequestsSrem getKeyRequestSmembers
#define getKeyRequestsSdiffstore getKeyRequestsSinterstore
#define getKeyRequestsSunionstore getKeyRequestsSinterstore
int getKeyRequestSmembers(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestSmove(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsSinterstore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZunionstore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZinterstore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZdiffstore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsRpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBrpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsLpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBlpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsRpoplpush(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsLmove(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsLindex(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define getKeyRequestsLset getKeyRequestsLindex
int getKeyRequestsLrange(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsLtrim(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsLmpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBlmpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZAdd(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZScore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZMScore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZincrby(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZrange(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZrangestore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsSinterstore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZpopMin(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZpopMax(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZmpop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZrangeByScore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZrevrangeByScore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZremRangeByScore1(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define getKeyRequestsZremRangeByScore getKeyRequestsZrangeByScore
int getKeyRequestsZrevrangeByLex(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZrangeByLex(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZremRangeByLex(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsZlexCount(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define getKeyRequestsSdiffstore getKeyRequestsSinterstore
#define getKeyRequestsSunionstore getKeyRequestsSinterstore
#define getKeyRequestsZrem getKeyRequestsZScore
int getKeyRequestsGeoAdd(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGeoRadius(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGeoHash(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGeoDist(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGeoSearch(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGeoSearchStore(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define getKeyRequestsGeoRadiusByMember getKeyRequestsGeoRadius
#define getKeyRequestsGeoPos getKeyRequestsGeoHash
int getKeyRequestsGtid(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsDebug(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsSetbit(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsGetbit(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBitcount(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBitpos(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBitop(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsBitField(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsMemory(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
int getKeyRequestsMemory(int dbid, struct redisCommand *cmd, robj **argv, int argc, struct getKeyRequestsResult *result);
#define GET_KEYREQUESTS_RESULT_INIT { {{0}}, NULL, NULL, 0, MAX_KEYREQUESTS_BUFFER}
typedef struct getKeyRequestsResult {
keyRequest buffer[MAX_KEYREQUESTS_BUFFER];
keyRequest *key_requests;
swapCmdTrace *swap_cmd;
int num;
int size;
} getKeyRequestsResult;
void getKeyRequestsPrepareResult(getKeyRequestsResult *result, int numswaps);
void getKeyRequestsAppendSubkeyResult(getKeyRequestsResult *result, int level, MOVE robj *key, int num_subkeys, MOVE robj **subkeys, int cmd_intention, int cmd_intention_flags, uint64_t cmd_flags, int dbid);
void getKeyRequestsFreeResult(getKeyRequestsResult *result);
void getKeyRequestsAttachSwapTrace(getKeyRequestsResult * result, swapCmdTrace *swap_cmd, int from_include, int to_exclude);
void getKeyRequestsAppendRangeResult(getKeyRequestsResult *result, int level, MOVE robj *key, int arg_rewrite0, int arg_rewrite1, int num_ranges, MOVE range *ranges, int cmd_intention, int cmd_intention_flags, uint64_t cmd_flags, int dbid);
#define SWAP_PERSIST_VERSION_NO 0
#define SWAP_PERSIST_VERSION_INITIAL 1
typedef struct persistingKeyEntry {
listNode *ln;
uint64_t version;
mstime_t mstime;
int state;
} persistingKeyEntry;
persistingKeyEntry *persistingKeyEntryNew(listNode *ln, uint64_t version, mstime_t mstime);
void persistingKeyEntryFree(void *privdata, void *val);
typedef struct persistingKeys {
list *todo;
list *doing;
dict *map;
} persistingKeys;
typedef struct persistingKeysTodoIter {
persistingKeys *keys;
listIter li;
} persistingKeysTodoIter;
persistingKeys *persistingKeysNew(void);
void persistingKeysFree(persistingKeys *keys);
int persistingKeysPut(persistingKeys *keys, sds key, uint64_t version, mstime_t time);
persistingKeyEntry *persistingKeysLookup(persistingKeys *keys, sds key);
int persistingKeysDelete(persistingKeys *keys, sds key);
size_t persistingKeysCount(persistingKeys *keys);
size_t persistingKeysUsedMemory(persistingKeys *keys);
void persistingKeysInitTodoIterator(persistingKeysTodoIter *iter, persistingKeys *keys);
void persistingKeysDeinitTodoIterator(persistingKeysTodoIter *iter);
sds persistingKeysTodoIterNext(persistingKeysTodoIter *iter, persistingKeyEntry **entry);
#define SWAP_PERSIST_MAX_KEYS_PER_LOOP 1024
typedef struct swapPersistStat {
long long add_succ;
long long add_ignored;
long long started;
long long rewind_dirty;
long long rewind_newer;
long long ended;
long long keep_data;
long long dont_keep;
} swapPersistStat;
typedef struct swapPersistCtx {
int keep;
uint64_t version;
persistingKeys **keys; /* one for each db */
long long inprogress_count; /* current inprogrss persist count */
long long inprogress_limit; /* current inprogress limit */
swapPersistStat stat;
} swapPersistCtx;
swapPersistCtx *swapPersistCtxNew(void);
void swapPersistCtxFree(swapPersistCtx *ctx);
size_t swapPersistCtxKeysCount(swapPersistCtx *ctx);
size_t swapPersistCtxUsedMemory(swapPersistCtx *ctx);
mstime_t swapPersistCtxLag(swapPersistCtx *ctx);
void swapPersistCtxAddKey(swapPersistCtx *ctx, redisDb *db, robj *key);
void swapPersistCtxPersistKeys(swapPersistCtx *ctx);
sds genSwapPersistInfoString(sds info);
void swapPersistKeyRequestFinished(swapPersistCtx *ctx, int dbid, robj *key, uint64_t persist_version);
void loadDataFromDisk(void);
void swap_loadDataFromDisk(void);
int submitEvictClientRequest(client *c, robj *key, int persist_keep, uint64_t persist_version);
#define setObjectPersistKeep(o) do { \
if (o) o->persist_keep = 1; \
} while(0)
#define clearObjectPersistKeep(o) do { \
if (o) o->persist_keep = 0; \
} while(0)
#define overwriteObjectPersistKeep(o,pk) do { \
if (o) o->persist_keep = pk; \
} while(0)
#define getObjectPersistKeep(o) ((o) ? o->persist_keep : 0)
#define setObjectPersistent(o) do { \
if (o) o->persistent = 1; \
} while(0)
#define clearObjectPersistent(o) do { \
if (o) o->persistent = 0; \
} while(0)
#define overwriteObjectPersistent(o,pk) do { \
if (o) o->persistent = pk; \
} while(0)
#define getObjectPersistent(o) ((o) ? o->persistent : 0)
#define setObjectMetaDirty(o) do { \
if (o) o->dirty_meta = 1; \
} while(0)
#define setObjectDataDirty(o) do { \
if (o) o->dirty_data = 1; \
} while(0)
#define setObjectDirty(o) do { \
setObjectMetaDirty(o); \
setObjectDataDirty(o); \
} while(0)
#define clearObjectMetaDirty(o) do { \
if (o) o->dirty_meta = 0; \
} while(0)
#define clearObjectDataDirty(o) do { \
if (o) o->dirty_data = 0; \
} while(0)
#define clearObjectDirty(o) do { \
clearObjectMetaDirty(o); \
clearObjectDataDirty(o); \
} while(0)
#define schedulePersistIfNeeded(dbid,key) do { \
if (server.swap_persist_enabled) swapPersistCtxAddKey(server.swap_persist_ctx,server.db+dbid,key); \
} while (0)
#define setObjectMetaDirtyPersist(dbid,key,o) do { \
setObjectMetaDirty(o); \
schedulePersistIfNeeded(dbid,key); \
} while (0)
#define setObjectDataDirtyPersist(dbid,key,o) do { \
setObjectDataDirty(o); \
schedulePersistIfNeeded(dbid,key); \
} while (0)
#define setObjectDirtyPersist(dbid,key,o) do { \
setObjectDirty(o); \
schedulePersistIfNeeded(dbid,key); \
} while (0)
#define objectIsMetaDirty(o) ((o)->dirty_meta)
#define objectIsDataDirty(o) ((o)->dirty_data)
#define objectIsDirty(o) (objectIsMetaDirty(o) || objectIsDataDirty(o))
static inline void dbSetDirty(redisDb *db, robj *key) {
kvobj *o = lookupKeyRead(db,key);
if (o) setObjectDirtyPersist(db->id,key,o);
}
static inline void dbSetMetaDirty(redisDb *db, robj *key) {
kvobj *o = lookupKeyRead(db,key);
if (o) setObjectMetaDirty(o);
}
/* Object meta */
#define SWAP_VERSION_ZERO 0
#define SWAP_VERSION_MAX UINT64_MAX
typedef enum {
NORMAL_MODE = 0,
RORDB_MODE,
} meta_encode_mode;
extern dictType objectMetaDictType;
struct objectMeta;
typedef struct objectMetaType {
sds (*encodeObjectMeta) (struct objectMeta *object_meta, void *aux, int meta_enc_mode);
int (*decodeObjectMeta) (struct objectMeta *object_meta, const char* extend, size_t extlen);
int (*objectIsHot)(struct objectMeta *object_meta, robj *value);
void (*free)(struct objectMeta *object_meta);
void (*duplicate)(struct objectMeta *dup_meta, struct objectMeta *object_meta);
int (*equal)(struct objectMeta *oma, struct objectMeta *omb);
int (*rebuildFeed)(struct objectMeta *rebuild_meta, uint64_t version, const char *subkey, size_t sublen, robj *subval);
} objectMetaType;
typedef struct objectMeta {
uint64_t version;
unsigned swap_type:4;
union {
long long len:60;
unsigned long long ptr:60;
};
} objectMeta;
extern objectMetaType lenObjectMetaType;
extern objectMetaType listObjectMetaType;
extern objectMetaType bitmapObjectMetaType;
static inline void swapInitVersion(void) { server.swap_key_version = 1; }
static inline void swapSetVersion(uint64_t version) { server.swap_key_version = version; }
static inline uint64_t swapGetAndIncrVersion(void) { return server.swap_key_version++; }
int buildObjectMeta(int swap_type, uint64_t version, const char *extend, size_t extlen, OUT objectMeta **pobject_meta);
objectMeta *dupObjectMeta(objectMeta *object_meta);
void freeObjectMeta(objectMeta *object_meta);
sds objectMetaEncode(struct objectMeta *object_meta, int meta_enc_mode);
int objectMetaDecode(struct objectMeta *object_meta, const char *extend, size_t extlen);
int keyIsHot(objectMeta *object_meta, robj *value);
int keyIsPureHot(objectMeta *object_meta, robj *value);
sds dumpObjectMeta(objectMeta *object_meta);
int objectMetaEqual(struct objectMeta *oma, struct objectMeta *omb);
int objectMetaRebuildFeed(struct objectMeta *rebuild_meta, uint64_t version, const char *subkey, size_t sublen, robj *subval);
static inline void *objectMetaGetPtr(objectMeta *object_meta) {
return (void*)(unsigned long long)object_meta->ptr;
}
static inline void objectMetaSetPtr(objectMeta *object_meta, void *ptr) {
object_meta->ptr = (unsigned long long)ptr;
}
objectMeta *createObjectMeta(int swap_type, uint64_t version);
objectMeta *createLenObjectMeta(int swap_type, uint64_t version, size_t len);
sds encodeLenObjectMeta(struct objectMeta *object_meta, void *aux, int meta_enc_mode);
int decodeLenObjectMeta(struct objectMeta *object_meta, const char *extend, size_t extlen);
int lenObjectMetaIsHot(struct objectMeta *object_meta, robj *value);
objectMeta *lookupMeta(redisDb *db, robj *key);
int tryReplaceMetaKey(redisDb *db, dictEntry* de, kvobj* newkey);
void dbAddMeta(redisDb *db, robj *key, objectMeta *m);
int dbDeleteMeta(redisDb *db, robj *key);
typedef struct swapObjectMeta {
objectMetaType *omtype;
objectMeta *object_meta;
objectMeta *cold_meta;
robj *value;
} swapObjectMeta;
#define initStaticSwapObjectMeta(_som,_omtype,_object_meta,_value) do { \
_som.omtype = _omtype; \
_som.object_meta = _object_meta; \
_som.value = _value; \
} while(0)
static inline int swapObjectMetaIsHot(swapObjectMeta *som) {
if (som->value == NULL) return 0;
serverAssert((som->object_meta->swap_type == SWAP_TYPE_BITMAP && som->value->type == OBJ_STRING) || som->object_meta->swap_type == som->value->type);
if (som->omtype->objectIsHot) {
return som->omtype->objectIsHot(som->object_meta,som->value);
} else {
return 0;
}
}
/* bitmap marker */
objectMeta *createBitmapObjectMarker();
int bitmapObjectMetaIsMarker(objectMeta *object_meta);
int bitmapSetObjectMarkerIfNotExist(redisDb *db, robj *key);
int bitmapClearObjectMarkerIfExist(redisDb *db, robj *key);
void bitmapMetaTransToMarkerIfNeeded(objectMeta *object_meta);
void bitmapMarkerTransToMetaIfNeeded(objectMeta *object_meta, robj *value);
/* Data */
#define SWAP_DATA_ABSENT_SUBKEYS_INIT 4
#define SWAP_DATA_ABSENT_SUBKEYS_LINEAR 1024
typedef struct swapDataAbsentSubkey {
size_t count;
size_t capacity;
sds *subkeys;
} swapDataAbsentSubkey;
#define SWAP_ANA_THD_MAIN 0
#define SWAP_ANA_THD_SWAP 1
static inline int swapDataAnaSwapType(robj *value, objectMeta *object_meta) {
if (object_meta) return object_meta->swap_type;
if (value) return value->type;
return -1;
}
/* SwapData represents key state when swap start. It is stable during
* key swapping, misc dynamic data are save in dataCtx. */
typedef struct swapData {
struct swapDataType *type;
struct objectMetaType *omtype;
redisDb *db;
robj *key; /*own*/
robj *value; /*own*/
long long expire;
objectMeta *object_meta; /* ref */
objectMeta *cold_meta; /* own, moved from exec */
objectMeta *new_meta; /* own */
int swap_type;
unsigned propagate_expire:1;
unsigned set_dirty:1;
unsigned set_dirty_meta:1;
unsigned persistence_deleted:1;
unsigned set_persist_keep:1;
unsigned reserved:27;
sds nextseek; /* own, moved from exec */
swapDataAbsentSubkey *absent;
robj *dirty_subkeys;
void *extends[2];
} swapData;
/* keyRequest: client request parse from command.
* swapData: key state when swap start.
* dataCtx: dynamic data when swapping. */
typedef struct swapDataType {
char* name;
uint64_t cmd_swap_flags;
int (*swapAna)(struct swapData *data, int thd, struct keyRequest *key_request, OUT int *intention, OUT uint32_t *intention_flags, void *datactx);
int (*swapAnaAction)(struct swapData *data, int intention, void *datactx, OUT int *action);
int (*encodeKeys)(struct swapData *data, int intention, void *datactx, OUT int *num, OUT int **cfs, OUT sds **rawkeys);
int (*encodeRange)(struct swapData *data, int intention, void *datactx, OUT int *limit, OUT uint32_t *flags, OUT int *cf, OUT sds *start, OUT sds *end);
int (*encodeData)(struct swapData *data, int intention, void *datactx, OUT int *num, OUT int **cfs, OUT sds **rawkeys, OUT sds **rawvals);
int (*decodeData)(struct swapData *data, int num, int *cfs, sds *rawkeys, sds *rawvals, OUT void **decoded);
int (*swapIn)(struct swapData *data, MOVE void **result, void *datactx);
int (*swapOut)(struct swapData *data, void *datactx, int keep_data, OUT int *totally_out);
int (*swapDel)(struct swapData *data, void *datactx, int async);
void *(*createOrMergeObject)(struct swapData *data, MOVE void *decoded, void *datactx);
int (*cleanObject)(struct swapData *data, void *datactx, int keep_data);
int (*beforeCall)(struct swapData *data, keyRequest *key_request, client *c, void *datactx);
void (*free)(struct swapData *data, void *datactx);
int (*rocksDel)(struct swapData *data_, void *datactx_, int inaction, int num, int* cfs, sds *rawkeys, sds *rawvals, OUT int *outaction, OUT int *outnum, OUT int** outcfs,OUT sds **outrawkeys);
int (*mergedIsHot)(struct swapData *data, MOVE void *result, void *datactx);
void* (*getObjectMetaAux)(struct swapData *data, void *datactx);
} swapDataType;
swapData *createSwapData(redisDb *db, robj *key, robj *value, robj *dirty_subkeys);
int swapDataSetupMeta(swapData *d, int swap_type, long long expire, OUT void **datactx);
int swapDataAlreadySetup(swapData *d);
void swapDataMarkPropagateExpire(swapData *data);
int swapDataAna(swapData *d, int thd, struct keyRequest *key_request, int *intention, uint32_t *intention_flag, void *datactx);
int swapDataSwapAnaAction(swapData *data, int intention, void *datactx_, int *action);
sds swapDataEncodeMetaKey(swapData *d);
sds swapDataEncodeMetaVal(swapData *d, void *datactx);
int swapDataEncodeKeys(swapData *d, int intention, void *datactx, int *num, int **cfs, sds **rawkeys);
int swapDataEncodeData(swapData *d, int intention, void *datactx, int *num, int **cfs, sds **rawkeys, sds **rawvals);
int swapDataEncodeRange(struct swapData *data, int intention, void *datactx_, int *limit, uint32_t *flags, int *pcf, sds *start, sds *end);
int swapDataDecodeAndSetupMeta(swapData *d, sds rawval, OUT void **datactx);
int swapDataDecodeData(swapData *d, int num, int *cfs, sds *rawkeys, sds *rawvals, void **decoded);
int swapDataSwapIn(swapData *d, void **result, void *datactx);
int swapDataSwapOut(swapData *d, void *datactx, int keep_data, OUT int *totally_out);
int swapDataSwapDel(swapData *d, void *datactx, int async);
void *swapDataCreateOrMergeObject(swapData *d, MOVE void *decoded, void *datactx);
int swapDataCleanObject(swapData *d, void *datactx, int keep_data);
int swapDataBeforeCall(swapData *d, keyRequest *key_request, client *c, void *datactx);
int swapDataKeyRequestFinished(swapData *data);
char swapDataGetObjectAbbrev(robj *value);
void swapDataFree(swapData *data, void *datactx);
int swapDataMergedIsHot(swapData *d, void *result, void *datactx);
void swapDataRetainAbsentSubkeys(swapData *data, int num, int *cfs, sds *rawkeys, sds *rawvals);
void swapDataMergeAbsentSubkey(swapData *data);
int swapDataMayContainSubkey(swapData *data, int thd, robj *subkey);
void *swapDataGetObjectMetaAux(swapData *data, void *datactx);
static inline void swapDataSetObjectMeta(swapData *d, objectMeta *object_meta) {
d->object_meta = object_meta;
}
static inline void swapDataSetColdObjectMeta(swapData *d, MOVE objectMeta *cold_meta) {
d->cold_meta = cold_meta;
}
static inline void swapDataSetNewObjectMeta(swapData *d, MOVE objectMeta *new_meta) {
d->new_meta = new_meta;
}
static inline int swapDataIsCold(swapData *data) {
return data->value == NULL;
}
static inline int swapDataIsHot(swapData *data) {
swapObjectMeta som;
initStaticSwapObjectMeta(som,data->omtype,data->object_meta,data->value);
return swapObjectMetaIsHot(&som);
}
static inline objectMeta *swapDataObjectMeta(swapData *d) {
serverAssert(
!(d->object_meta && d->new_meta) ||
!(d->object_meta && d->cold_meta) ||
!(d->new_meta && d->cold_meta));
if (d->object_meta) return d->object_meta;
if (d->cold_meta) return d->cold_meta;
return d->new_meta;
}
static inline uint64_t swapDataObjectVersion(swapData *d) {
objectMeta *object_meta = swapDataObjectMeta(d);
return object_meta ? object_meta->version : 0;
}
static inline int swapDataPersisted(swapData *d) {
if (d->swap_type == SWAP_TYPE_BITMAP && d->object_meta) {
return !bitmapObjectMetaIsMarker(d->object_meta);
}
return d->object_meta || d->cold_meta;
}
static inline void swapDataObjectMetaModifyLen(swapData *d, int delta) {
objectMeta *object_meta = swapDataObjectMeta(d);
object_meta->len += delta;
serverAssert(object_meta->len >= 0);
}
static inline void swapDataObjectMetaSetPtr(swapData *d, void *ptr) {
objectMeta *object_meta = swapDataObjectMeta(d);
object_meta->ptr = (unsigned long long)(long)ptr;
}
/* persist request keeps value in memory when maxmemory not reached or
* data originally not cold (no need to swap in). */
static inline int swapDataPersistKeepData(swapData *d, uint32_t cmd_intention_flags, int may_keep_data) {
int keep_data = (cmd_intention_flags & SWAP_OUT_PERSIST) &&
(getObjectPersistKeep(d->value) || cmd_intention_flags&SWAP_OUT_KEEP_DATA) &&
may_keep_data;
if (server.swap_persist_enabled && server.swap_persist_ctx) {
swapPersistStat *stat = &server.swap_persist_ctx->stat;
if (keep_data)
stat->keep_data++;
else
stat->dont_keep++;
}
return keep_data;
}
void swapDataTurnWarmOrHot(swapData *data);
void swapDataTurnCold(swapData *data);
void swapDataTurnDeleted(swapData *data,int del_skip);
int swapDataObjectMergedIsHot(swapData *data, void *result, void *datactx);
#define setMergedIsHot swapDataObjectMergedIsHot
#define hashMergedIsHot swapDataObjectMergedIsHot
#define zsetMergedIsHot swapDataObjectMergedIsHot
#define wholeKeyMergedIsHot swapDataObjectMergedIsHot
/* Debug msgs */
#ifdef SWAP_DEBUG
#define MAX_MSG 64
#define MAX_STEPS 16
typedef struct swapDebugMsgs {
char identity[MAX_MSG];
struct swapCtxStep {
char name[MAX_MSG];
char info[MAX_MSG];
} steps[MAX_STEPS];
int index;
} swapDebugMsgs;
void swapDebugMsgsInit(swapDebugMsgs *msgs, char *identity);
#ifdef __GNUC__
void swapDebugMsgsAppend(swapDebugMsgs *msgs, char *step, char *fmt, ...)
__attribute__((format(printf, 3, 4)));
void swapDebugBatchMsgsAppend(swapExecBatch *batch, char *step, char *fmt, ...)
__attribute__((format(printf, 3, 4)));
#else
void swapDebugMsgsAppend(swapDebugMsgs *msgs, char *step, char *fmt, ...);
void swapDebugBatchMsgsAppend(swapExecBatch *batch, char *step, char *fmt, ...);
#endif
void swapDebugMsgsDump(swapDebugMsgs *msgs);
#define DEBUG_MSGS_INIT(msgs, identity) do { if (msgs) swapDebugMsgsInit(msgs, identity); } while (0)
#define DEBUG_MSGS_APPEND(msgs, step, ...) do { if (msgs) swapDebugMsgsAppend(msgs, step, __VA_ARGS__); } while (0)
#define DEBUG_BATCH_MSGS_APPEND(batch, step, ...) do { if (batch) swapDebugBatchMsgsAppend(batch, step, __VA_ARGS__); } while (0)
#else
#define DEBUG_MSGS_INIT(msgs, identity)
#define DEBUG_MSGS_APPEND(msgs, step, ...)
#define DEBUG_BATCH_MSGS_APPEND(batch, step, ...)
#endif
/* Swap */
#define SWAP_ERR_SETUP_FAIL -100
#define SWAP_ERR_SETUP_UNEXPECTED_SWAP_TYPE -101
#define SWAP_ERR_SETUP_UNSUPPORTED -102
#define SWAP_ERR_DATA_FAIL -200
#define SWAP_ERR_DATA_ANA_FAIL -201
#define SWAP_ERR_DATA_DECODE_FAIL -202
#define SWAP_ERR_DATA_FIN_FAIL -203
#define SWAP_ERR_DATA_UNEXPECTED_INTENTION -204
#define SWAP_ERR_DATA_DECODE_META_FAILED -205
#define SWAP_ERR_DATA_WRONG_TYPE_ERROR -206
#define SWAP_ERR_EXEC_FAIL -300
#define SWAP_ERR_EXEC_UNEXPECTED_ACTION -302
#define SWAP_ERR_EXEC_ROCKSDB_FLUSH_FAIL -303
#define SWAP_ERR_EXEC_UNEXPECTED_UTIL -304
#define SWAP_ERR_METASCAN_FAIL -400
#define SWAP_ERR_METASCAN_UNSUPPORTED_IN_MULTI -401
#define SWAP_ERR_METASCAN_SESSION_UNASSIGNED -402
#define SWAP_ERR_METASCAN_SESSION_INPROGRESS -403
#define SWAP_ERR_METASCAN_SESSION_SEQUNMATCH -404
#define SWAP_ERR_RIO_FAIL -500
#define SWAP_ERR_RIO_GET_FAIL -501
#define SWAP_ERR_RIO_PUT_FAIL -502
#define SWAP_ERR_RIO_DEL_FAIL -503
#define SWAP_ERR_RIO_ITER_FAIL -504
#define SWAP_ERR_RIO_OOM -505
struct swapCtx;
typedef void (*clientKeyRequestFinished)(client *c, struct swapCtx *ctx);
typedef struct swapCtx {
client *c;
keyRequest key_request[1];
swapData *data;
void *datactx;
clientKeyRequestFinished finished;
int errcode;
void *swap_lock;
#ifdef SWAP_DEBUG
swapDebugMsgs msgs;
#endif
void *pd;
} swapCtx;
swapCtx *swapCtxCreate(client *c, keyRequest *key_request, clientKeyRequestFinished finished, void* pd);
void swapCtxSetSwapData(swapCtx *ctx, MOVE swapData *data, MOVE void *datactx);
void swapCtxFree(swapCtx *ctx);
typedef enum {
SWAP_REWIND_OFF = 0, /* rewind off */
SWAP_REWIND_WRITE, /* rewind client with write commands */
SWAP_REWIND_ALL, /* rewind client with any commands */
} swap_rewind_type;
void startSwapRewind(swap_rewind_type rewind_type);
void endSwapRewind(void);
void freeClientSwapCmdTrace(client *c);
/* see server.swap_req_submitted */
#define REQ_SUBMITTED_NONE 0
#define REQ_SUBMITTED_BGSAVE (1ULL<<0)
#define REQ_SUBMITTED_REPL_START (1ULL<<1)
/* Hash */
typedef struct hashSwapData {
swapData d;
} hashSwapData;
#define BIG_DATA_CTX_FLAG_NONE 0
#define BIG_DATA_CTX_FLAG_MOCK_VALUE (1U<<0)
#define BASE_SWAP_CTX_TYPE_SUBKEY 0
#define BASE_SWAP_CTX_TYPE_SAMPLE 1
typedef struct baseBigDataCtx {
int type;
union {
struct {
int num;
robj **subkeys;
} sub;
struct {
int count;
} spl;
};
int ctx_flag;
} baseBigDataCtx;
typedef struct hashDataCtx {
baseBigDataCtx ctx;
} hashDataCtx;
int swapDataSetupHash(swapData *d, OUT void **datactx);
#define hashObjectMetaType lenObjectMetaType
#define createHashObjectMeta(version, len) createLenObjectMeta(OBJ_HASH, version, len)
size_t hashMetaLength(redisDb *db, robj *key);
/* String */
typedef struct wholeKeySwapData {
swapData d;
} wholeKeySwapData;
int swapDataSetupWholeKey(swapData *d, OUT void **datactx);
/* Set */
typedef struct setSwapData {
swapData d;
} setSwapData;
typedef struct setDataCtx {
baseBigDataCtx ctx;
} setDataCtx;
int swapDataSetupSet(swapData *d, OUT void **datactx);
#define setObjectMetaType lenObjectMetaType
#define createSetObjectMeta(version, len) createLenObjectMeta(OBJ_SET, version, len)
unsigned long swap_setTypeSize(const objectMeta *meta, const robj *o);
unsigned long swap_setTypeSizeLookup(redisDb *db, robj *key, const robj *o);
void swap_scardCommand(client *c);
/* List */
typedef struct listSwapData {
swapData d;
} listSwapData;
typedef struct listDataCtx {
struct listMeta *swap_meta;
argRewriteRequest arg_reqs[2];
int ctx_flag;
} listDataCtx;
objectMeta *createListObjectMeta(uint64_t version, MOVE struct listMeta *list_meta);
int swapDataSetupList(swapData *d, void **pdatactx);
typedef struct argRewrite {
argRewriteRequest arg_req;
robj *orig_arg; /* own */
} argRewrite;
#define ARG_REWRITES_MAX 2
typedef struct argRewrites {
int num;
argRewrite rewrites[ARG_REWRITES_MAX];
} argRewrites;
argRewrites *argRewritesCreate(void);
void argRewritesAdd(argRewrites *arg_rewrites, argRewriteRequest arg_req, MOVE robj *orig_arg);
void argRewritesReset(argRewrites *arg_rewrites);
void argRewritesFree(argRewrites *arg_rewrites);
void argRewritesAdd(argRewrites *arg_rewrites, argRewriteRequest arg_req, MOVE robj *orig_arg);
void clientArgRewritesRestore(client *c);
void clientArgRewrite(client *c, argRewriteRequest arg_req, MOVE robj *new_arg);
long swapListTypeLength(robj *list, objectMeta *object_meta);
void swapListTypePush(robj *subject, robj *value, int where, redisDb *db, robj *key);
robj *swapListTypePop(robj *subject, int where, redisDb *db, robj *key);
void swapListMetaDelRange(redisDb *db, robj *key, long ltrim, long rtrim);
void swapListMetaTrimCold(redisDb *db, robj *key, long ltrim, long rtrim,
long long orig_lstart, long long orig_lend);
/* zset */
typedef struct zsetSwapData {
swapData sd;
} zsetSwapData;
#define ZSET_SWAP_CTX_TYPE_NONE 0
#define ZSET_SWAP_CTX_TYPE_ZS 1
typedef struct zsetDataCtx {
baseBigDataCtx bdc;
int type;
union {
struct {
zrangespec* rangespec;
int reverse;
int limit;
} zs;
};
} zsetDataCtx;