申请一个新分片，从小到大[0,4095]寻找一个为占用的分片

async def _lease_shard(self):
        """ 申请一个新分片，从小到大[0,4095]寻找一个为占用的分片 """

        prefix = self._prefix + '/shards/'
        self._lease = await self._client.grant_lease(ttl=self._shard_ttl)

        timestamp_bytes = (0).to_bytes(4, byteorder='big')

        retries = 0
        while True:
            shard_subidx = len(prefix)
            shard_id = 0

            # 找到未使用的最小分片号
            records = await self._client.range_keys(range_prefix(prefix))
            nums = sorted(int_fromhexbytes(k[shard_subidx:]) for k, _ in records)
            for i, n in enumerate(nums):
                if n > i:
                    shard_id = i
                    break
            else:
                shard_id = len(nums)

            shard_id = int_tohex(shard_id, length=2)

            logger.debug(f'leasing shard#{shard_id}, retry={retries}')

            shard_path = f'{self._prefix}/shards/{shard_id}'
            is_success, _ = await self._client.txn(compare=[
                    transaction.Version(shard_path) == 0 
                ], success=[
                    KV.put.txn(shard_path, timestamp_bytes, lease=self._lease)
                ])

            if is_success:
                self._shard_id = shard_id
                self._timestamp = None
                self._seqnum = None
                break
            else:
                logger.debug(f'failed in leasing shard#{shard_id}: retry {retries}')
                await _random_nap(retries)
                retries += 1

                if retries > 10:
                    raise ValueError('out of retries')