public List<BlockedClient<T>> getBlockedClients(int page, int size) {
        int offset = size * page;
        size = Math.min(size, blockedClientIdToBlockEndTimeMillis.size() - offset);
        if (size <= 0) {
            return Collections.emptyList();
        }
        List<BlockedClient<T>> blockedClients = new ChunkedArrayList<>();
        Iterator<Map.Entry<T, Long>> iterator = blockedClientIdToBlockEndTimeMillis.entrySet()
                .iterator();
        long now = System.currentTimeMillis();
        int i = 0;
        long blockEndTimeMillis;
        while (i < offset && iterator.hasNext()) {
            Map.Entry<T, Long> entry = iterator.next();
            blockEndTimeMillis = entry.getValue();
            if (blockEndTimeMillis < now) {
                iterator.remove();
                blockedClientSkipList
                        .remove(new BlockedClient<>(entry.getKey(), blockEndTimeMillis));
            } else {
                i++;
            }
        }
        i = 0;
        while (i < size && iterator.hasNext()) {
            Map.Entry<T, Long> entry = iterator.next();
            blockEndTimeMillis = entry.getValue();
            if (blockEndTimeMillis < now) {
                iterator.remove();
                blockedClientSkipList
                        .remove(new BlockedClient<>(entry.getKey(), blockEndTimeMillis));
            } else {
                blockedClients.add(new BlockedClient<>(entry.getKey(), blockEndTimeMillis));
                i++;
            }
        }
        return blockedClients;
    }
Used to remove the local expired blocked clients quickly, even if there are a lot of blocked
clients so that we can run eviction more frequently.

@implNote It is acceptable to store the same IP or the user ID with different block times in
          the skip list because it is how the skip list works.
turms-server-common/src/main/java/im/turms/server/common/domain/blocklist/manager/BlocklistServiceManager.java