Skip to content

Commit 0efad57

Browse files
committed
feat(bitop): Support DIFF, DIFF1, ANDOR, and ONE for command BITOP
1 parent 921078f commit 0efad57

File tree

3 files changed

+120
-2
lines changed

3 files changed

+120
-2
lines changed

src/commands/cmd_bit.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ class CommandBitOp : public Commander {
225225
op_flag_ = kBitOpXor;
226226
else if (opname == "not")
227227
op_flag_ = kBitOpNot;
228+
else if (opname == "diff")
229+
op_flag_ = kBitOpDiff;
230+
else if (opname == "diff1")
231+
op_flag_ = kBitOpDiff1;
232+
else if (opname == "andor")
233+
op_flag_ = kBitOpAndOr;
234+
else if (opname == "one")
235+
op_flag_ = kBitOpOne;
228236
else
229237
return {Status::RedisInvalidCmd, errInvalidSyntax};
230238
if (op_flag_ == kBitOpNot && args.size() != 4) {

src/types/redis_bitmap.cc

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,11 +589,94 @@ rocksdb::Status Bitmap::BitOp(engine::Context &ctx, BitOpFlags op_flag, const st
589589
j += sizeof(uint64_t) * 4;
590590
frag_minlen -= sizeof(uint64_t) * 4;
591591
}
592+
} else if (op_flag == kBitOpDiff
593+
|| op_flag == kBitOpDiff1
594+
|| op_flag == kBitOpAndOr) {
595+
size_t processed = 0;
596+
size_t k = 0;
597+
598+
while(frag_minlen >= sizeof(uint64_t)*4) {
599+
for (uint64_t i = 1; i < frag_numkeys; i++) {
600+
lres[0] |= lp[i][k+0];
601+
lres[1] |= lp[i][k+1];
602+
lres[2] |= lp[i][k+2];
603+
lres[3] |= lp[i][k+3];
604+
}
605+
k += 4;
606+
lres += 4;
607+
j += sizeof(uint64_t) * 4;
608+
frag_minlen -= sizeof(uint64_t) * 4;
609+
processed += sizeof(uint64_t) * 4;
610+
}
611+
612+
lres = reinterpret_cast<uint64_t *>(frag_res.get());
613+
auto *first_key = reinterpret_cast<const uint64_t *>(fragments[0].data());
614+
switch (op_flag) {
615+
case kBitOpDiff:
616+
for (uint64_t i = 0; i < processed; i += sizeof(uint64_t) * 4) {
617+
lres[0] = (first_key[0] & ~lres[0]);
618+
lres[1] = (first_key[1] & ~lres[1]);
619+
lres[2] = (first_key[2] & ~lres[2]);
620+
lres[3] = (first_key[3] & ~lres[3]);
621+
lres+=4;
622+
first_key += 4;
623+
}
624+
break;
625+
case kBitOpDiff1:
626+
for (uint64_t i = 0; i < processed; i += sizeof(uint64_t) * 4) {
627+
lres[0] = (~first_key[0] & lres[0]);
628+
lres[1] = (~first_key[1] & lres[1]);
629+
lres[2] = (~first_key[2] & lres[2]);
630+
lres[3] = (~first_key[3] & lres[3]);
631+
lres += 4;
632+
first_key += 4;
633+
}
634+
break;
635+
case kBitOpAndOr:
636+
for (uint64_t i = 0; i < processed; i += sizeof(uint64_t) * 4) {
637+
lres[0] = (first_key[0] & lres[0]);
638+
lres[1] = (first_key[1] & lres[1]);
639+
lres[2] = (first_key[2] & lres[2]);
640+
lres[3] = (first_key[3] & lres[3]);
641+
lres += 4;
642+
first_key += 4;
643+
}
644+
break;
645+
}
646+
} else if (op_flag == kBitOpOne) {
647+
uint64_t lcommon_bits[4];
648+
size_t k = 0;
649+
650+
while(frag_minlen >= sizeof(uint64_t)*4) {
651+
memset(lcommon_bits, 0, sizeof(lcommon_bits));
652+
653+
for (size_t i = 1; i < frag_numkeys; i++) {
654+
lcommon_bits[0] |= (lres[0] & lp[i][k+0]);
655+
lcommon_bits[1] |= (lres[1] & lp[i][k+1]);
656+
lcommon_bits[2] |= (lres[2] & lp[i][k+2]);
657+
lcommon_bits[3] |= (lres[3] & lp[i][k+3]);
658+
659+
lres[0] ^= lp[i][k+0];
660+
lres[1] ^= lp[i][k+1];
661+
lres[2] ^= lp[i][k+2];
662+
lres[3] ^= lp[i][k+3];
663+
}
664+
665+
lres[0] &= ~lcommon_bits[0];
666+
lres[1] &= ~lcommon_bits[1];
667+
lres[2] &= ~lcommon_bits[2];
668+
lres[3] &= ~lcommon_bits[3];
669+
670+
k += 4;
671+
lres += 4;
672+
j += sizeof(uint64_t) * 4;
673+
frag_minlen -= sizeof(uint64_t) * 4;
674+
}
592675
}
593676
}
594677
#endif
595678

596-
uint8_t output = 0, byte = 0;
679+
uint8_t output = 0, byte = 0, disjunction = 0, common_bits = 0;
597680
for (; j < frag_maxlen; j++) {
598681
output = (fragments[0].size() <= j) ? 0 : fragments[0][j];
599682
if (op_flag == kBitOpNot) output = ~output;
@@ -609,11 +692,34 @@ rocksdb::Status Bitmap::BitOp(engine::Context &ctx, BitOpFlags op_flag, const st
609692
case kBitOpXor:
610693
output ^= byte;
611694
break;
695+
case kBitOpDiff:
696+
case kBitOpDiff1:
697+
case kBitOpAndOr:
698+
disjunction |= byte;
699+
break;
700+
case kBitOpOne:
701+
common_bits |= (output & byte);
702+
output ^= byte;
703+
output &= ~common_bits;
704+
break;
612705
default:
613706
break;
614707
}
615708
}
616-
frag_res[j] = output;
709+
switch(op_flag) {
710+
case kBitOpDiff:
711+
frag_res[j] = (output & ~disjunction);
712+
break;
713+
case kBitOpDiff1:
714+
frag_res[j] = (~output & disjunction);
715+
break;
716+
case kBitOpAndOr:
717+
frag_res[j] = (output & disjunction);
718+
break;
719+
default:
720+
frag_res[j] = output;
721+
break;
722+
}
617723
}
618724

619725
if (op_flag == kBitOpNot) {

src/types/redis_bitmap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ enum BitOpFlags {
3434
kBitOpOr,
3535
kBitOpXor,
3636
kBitOpNot,
37+
kBitOpDiff,
38+
kBitOpDiff1,
39+
kBitOpAndOr,
40+
kBitOpOne
3741
};
3842

3943
namespace redis {

0 commit comments

Comments
 (0)