<commit_before>import redis
from datetime import datetime, timedelta
import string
import random
import time
from collections import namedtuple


Lock = namedtuple("Lock", ("validity", "resource", "key"))


class Redlock(object):

    default_retry_count = 3
    default_retry_delay = 0.2
    clock_drift_factor = 0.01
    unlock_script = """
    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end"""

    def __init__(self, connection_list, retry_count=None, retry_delay=None):
        self.servers = []
        for connection_info in connection_list:
            try:
                if isinstance(connection_info, basestring):
                    server = redis.StrictRedis.from_url(connection_info)
                else:
                    server = redis.StrictRedis(**connection_info)
                self.servers.append(server)
            except Exception as e:
                raise Warning(str(e))
        self.quorum = (len(self.servers) / 2) + 1
        self.retry_count = retry_count or self.default_retry_count
        self.retry_delay = retry_delay or self.default_retry_delay

    def lock_instance(self, server, resource, val, ttl):
        try:
            return server.set(resource, val, nx=True, px=ttl)
        except:
            return False

    def unlock_instance(self, server, resource, val):
        try:
            server.eval(self.unlock_script, 1, resource, val)
        except:
            pass

    def get_unique_id(self):
        CHARACTERS = string.ascii_letters + string.digits
        return ''.join(random.choice(CHARACTERS) for _ in range(22))

    def lock(self, resource, ttl):
        retry = 0
        val = self.get_unique_id()
        while retry < self.retry_count:
            n = 0
            start_time = datetime.utcnow()
            for server in self.servers:
                if self.lock_instance(server, resource, val, ttl):
                    n += 1
            drift = (ttl * self.clock_drift_factor) + 2
            now_time = datetime.utcnow()
            elapsed_time_minus_drift = ((now_time - start_time) - timedelta(milliseconds=drift)).total_seconds() * 1000
            validity = ttl - elapsed_time_minus_drift
            if validity > 0 and n >= self.quorum:
                return Lock(validity, resource, val)
            else:
                for server in self.servers:
                    self.unlock_instance(server, resource, val)
                retry += 1
                time.sleep(self.retry_delay)
        return False

    def unlock(self, lock):
        for server in self.servers:
            self.unlock_instance(server, lock.resource, lock.key)

<commit_msg>Fix logic when calculating `validity`.<commit_after>import redis
import string
import random
import time
from collections import namedtuple


Lock = namedtuple("Lock", ("validity", "resource", "key"))


class Redlock(object):

    default_retry_count = 3
    default_retry_delay = 0.2
    clock_drift_factor = 0.01
    unlock_script = """
    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end"""

    def __init__(self, connection_list, retry_count=None, retry_delay=None):
        self.servers = []
        for connection_info in connection_list:
            try:
                if isinstance(connection_info, basestring):
                    server = redis.StrictRedis.from_url(connection_info)
                else:
                    server = redis.StrictRedis(**connection_info)
                self.servers.append(server)
            except Exception as e:
                raise Warning(str(e))
        self.quorum = (len(self.servers) / 2) + 1
        self.retry_count = retry_count or self.default_retry_count
        self.retry_delay = retry_delay or self.default_retry_delay

    def lock_instance(self, server, resource, val, ttl):
        try:
            return server.set(resource, val, nx=True, px=ttl)
        except:
            return False

    def unlock_instance(self, server, resource, val):
        try:
            server.eval(self.unlock_script, 1, resource, val)
        except:
            pass

    def get_unique_id(self):
        CHARACTERS = string.ascii_letters + string.digits
        return ''.join(random.choice(CHARACTERS) for _ in range(22))

    def lock(self, resource, ttl):
        retry = 0
        val = self.get_unique_id()

        # Add 2 milliseconds to the drift to account for Redis expires
        # precision, which is 1 millisecond, plus 1 millisecond min
        # drift for small TTLs.
        drift = int(ttl * self.clock_drift_factor) + 2

        while retry < self.retry_count:
            n = 0
            start_time = int(time.time() * 1000)
            for server in self.servers:
                if self.lock_instance(server, resource, val, ttl):
                    n += 1
            elapsed_time = int(time.time() * 1000) - start_time
            validity = int(ttl - elapsed_time - drift)
            if validity > 0 and n >= self.quorum:
                return Lock(validity, resource, val)
            else:
                for server in self.servers:
                    self.unlock_instance(server, resource, val)
                retry += 1
                time.sleep(self.retry_delay)
        return False

    def unlock(self, lock):
        for server in self.servers:
            self.unlock_instance(server, lock.resource, lock.key)

{'fraction_non_alphanumeric': 0.09132253956703656, 'fraction_numerical': 0.010369292341277061, 'mean_word_length': 2.0109529025191675, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4898792', 'n_tokens_mistral': 1645, 'n_tokens_neox': 1568, 'n_words': 400}