def unfollow(cls, from_user_id, to_user_id): if from_user_id == to_user_id: return 0 if not GateKeeper.is_switched_on('switch_friendship_to_hbase'): # https://docs.djangoproject.com/en/3.1/ref/models/querysets/#delete # Queryset 的 delete 操作返回两个值,一个是删了多少数据,一个是具体每种类型删了多少 # 为什么会出现多种类型数据的删除?因为可能因为 foreign key 设置了 cascade 出现级联 # 删除,也就是比如 A model 的某个属性是 B model 的 foreign key,并且设置了 # on_delete=models.CASCADE, 那么当 B 的某个数据被删除的时候,A 中的关联也会被删除。 # 所以 CASCADE 是很危险的,我们一般最好不要用,而是用 on_delete=models.SET_NULL # 取而代之,这样至少可以避免误删除操作带来的多米诺效应。 deleted, _ = Friendship.objects.filter( from_user_id=from_user_id, to_user_id=to_user_id, ).delete() return deleted instance = cls.get_follow_instance(from_user_id, to_user_id) if instance is None: return 0 HBaseFollowing.delete(from_user_id=from_user_id, created_at=instance.created_at) HBaseFollower.delete(to_user_id=to_user_id, created_at=instance.created_at) return 1
def follow(cls, from_user_id, to_user_id): if from_user_id == to_user_id: return None if not GateKeeper.is_switched_on('switch_friendship_to_hbase'): # create data in mysql return Friendship.objects.create( from_user_id=from_user_id, to_user_id=to_user_id, ) # create data in hbase # first we retrieve the current time and store it in a local variable # in case there are inconsistencies between the two records that we created in those two tables now = int(time.time() * 1000000) HBaseFollower.create( from_user_id=from_user_id, to_user_id=to_user_id, created_at=now, ) return HBaseFollowing.create( from_user_id=from_user_id, to_user_id=to_user_id, created_at=now, )
def follow(cls, from_user_id, to_user_id): if from_user_id == to_user_id: return None # update Redis cls.add_following_id_in_redis(from_user_id, to_user_id) # update DB if not GateKeeper.is_switch_on('switch_friendship_to_hbase'): # create data in MySQL return Friendship.objects.create( from_user_id=from_user_id, to_user_id=to_user_id, ) # create data in hbase now = int(time.time() * 1000000) HBaseFollower.create( from_user_id=from_user_id, to_user_id=to_user_id, created_at=now, ) return HBaseFollowing.create( from_user_id=from_user_id, to_user_id=to_user_id, created_at=now, )
def get_following_user_id_set(cls, from_user_id): # cache set in Redis name = FOLLOWINGS_PATTERN.format(user_id=from_user_id) user_id_set = RedisHelper.get_all_members_from_set(name) # cache hit, need to change b'123' -> 123 if user_id_set is not None: user_id_set_new = set([]) for user_id in user_id_set: if isinstance(user_id, bytes): user_id = user_id.decode('utf-8') user_id_set_new.add(int(user_id)) return user_id_set_new # cache miss if not GateKeeper.is_switch_on('switch_friendship_to_hbase'): friendships = Friendship.objects.filter(from_user_id=from_user_id) else: friendships = HBaseFollowing.filter(prefix=(from_user_id, None)) user_id_set = set([ fs.to_user_id for fs in friendships ]) # push in Redis RedisHelper.add_id_to_set(name, user_id_set) return user_id_set
def get_following_user_id_set(cls, from_user_id): # <todo> cache in redis set if not GateKeeper.is_switch_on('switch_friendship_to_hbase'): friendships = Friendship.objects.filter(from_user_id=from_user_id) else: friendships = HBaseFollowing.filter(prefix=(from_user_id, None)) user_id_set = set([fs.to_user_id for fs in friendships]) return user_id_set
def get_following_user_id_set(cls, from_user_id): # <TODO> cache in redis set if not GateKeeper.is_switched_on('switch_friendship_to_hbase'): friendships = Friendship.objects.filter(from_user_id=from_user_id) else: friendships = HBaseFollowing.filter(prefix=(from_user_id, None)) # we use a set to hold a data because it is fast to check whether an elements exists there user_id_set = set([fs.to_user_id for fs in friendships]) return user_id_set
def test_save_and_get(self): timestamp = self.ts_now following = HBaseFollowing(from_user_id=123, to_user_id=34, created_at=timestamp) following.save() instance = HBaseFollowing.get(from_user_id=123, created_at=timestamp) self.assertEqual(instance.from_user_id, 123) self.assertEqual(instance.to_user_id, 34) self.assertEqual(instance.created_at, timestamp) following.to_user_id = 456 following.save() instance = HBaseFollowing.get(from_user_id=123, created_at=timestamp) self.assertEqual(instance.to_user_id, 456) #object does not exist, return None instance = HBaseFollowing.get(from_user_id=123, created_at=self.ts_now) self.assertEqual(instance, None)
def unfollow(cls, from_user_id, to_user_id): if from_user_id == to_user_id: return 0 # update Redis cls.remove_following_id_in_redis(from_user_id, to_user_id) # update DB if not GateKeeper.is_switch_on('switch_friendship_to_hbase'): deleted, _ = Friendship.objects.filter( from_user_id=from_user_id, to_user_id=to_user_id, ).delete() return deleted instance = cls.get_follow_instance(from_user_id, to_user_id) if instance is None: return 0 HBaseFollowing.delete(from_user_id=from_user_id, created_at=instance.created_at) HBaseFollower.delete(to_user_id=to_user_id, created_at=instance.created_at) return 1
def follow(cls, from_user_id, to_user_id): if from_user_id == to_user_id: return None if not GateKeeper.is_switch_on('switch_friendship_to_hbase'): # create data in mysql return Friendship.objects.create( from_user_id=from_user_id, to_user_id=to_user_id, ) # create data in hbase now = int(time.time() * 1000000) HBaseFollower.create( from_user_id=from_user_id, to_user_id=to_user_id, created_at=now, ) return HBaseFollowing.create( from_user_id=from_user_id, to_user_id=to_user_id, created_at=now, )
def get_follow_instance(cls, from_user_id, to_user_id): followings = HBaseFollowing.filter(prefix=(from_user_id, None)) for follow in followings: if follow.to_user_id == to_user_id: return follow return None
def get_following_count(cls, from_user_id): if not GateKeeper.is_switched_on('switch_friendship_to_hbase'): return Friendship.objects.filter(from_user_id=from_user_id).count() followings = HBaseFollowing.filter(prefix=(from_user_id, None)) return len(followings)
def test_filter(self): HBaseFollowing.create(from_user_id=1, to_user_id=2, created_at=self.ts_now) HBaseFollowing.create(from_user_id=1, to_user_id=3, created_at=self.ts_now) HBaseFollowing.create(from_user_id=1, to_user_id=4, created_at=self.ts_now) followings = HBaseFollowing.filter(prefix=(1, )) self.assertEqual(3, len(followings)) self.assertEqual(followings[0].from_user_id, 1) self.assertEqual(followings[0].to_user_id, 2) self.assertEqual(followings[1].from_user_id, 1) self.assertEqual(followings[1].to_user_id, 3) self.assertEqual(followings[2].from_user_id, 1) self.assertEqual(followings[2].to_user_id, 4) # test limit results = HBaseFollowing.filter(prefix=(1, ), limit=1) self.assertEqual(len(results), 1) self.assertEqual(results[0].to_user_id, 2) results = HBaseFollowing.filter(prefix=(1, ), limit=2) self.assertEqual(len(results), 2) self.assertEqual(results[0].to_user_id, 2) self.assertEqual(results[1].to_user_id, 3) results = HBaseFollowing.filter(prefix=(1, ), limit=4) self.assertEqual(len(results), 3) self.assertEqual(results[0].to_user_id, 2) self.assertEqual(results[1].to_user_id, 3) self.assertEqual(results[2].to_user_id, 4) results = HBaseFollowing.filter(start=(1, results[1].created_at), limit=2) self.assertEqual(len(results), 2) self.assertEqual(results[0].to_user_id, 3) self.assertEqual(results[1].to_user_id, 4) # test reverse results = HBaseFollowing.filter(prefix=(1, ), limit=2, reverse=True) self.assertEqual(len(results), 2) self.assertEqual(results[0].to_user_id, 4) self.assertEqual(results[1].to_user_id, 3) results = HBaseFollowing.filter(start=(1, results[1].created_at), limit=2, reverse=True) self.assertEqual(len(results), 2) self.assertEqual(results[0].to_user_id, 3) self.assertEqual(results[1].to_user_id, 2)