add LRUCache

This commit is contained in:
clowwindy 2014-04-24 01:36:22 +08:00
parent 9ffb0320bb
commit 6834178a89
2 changed files with 75 additions and 3 deletions

62
shadowsocks/lru_cache.py Normal file
View file

@ -0,0 +1,62 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import collections
import logging
import heapq
import time
class LRUCache(collections.MutableMapping):
"""This class is not thread safe"""
def __init__(self, timeout=60, *args, **kwargs):
self.timeout = timeout
self.store = {}
self.time_to_keys = collections.defaultdict(list)
self.last_visits = []
self.update(dict(*args, **kwargs)) # use the free update to set keys
def __getitem__(self, key):
"O(logm)"
t = time.time()
self.time_to_keys[t].append(key)
heapq.heappush(self.last_visits, t)
return self.store[key]
def __setitem__(self, key, value):
"O(logm)"
t = time.time()
self.store[key] = value
self.time_to_keys[t].append(key)
heapq.heappush(self.last_visits, t)
def __delitem__(self, key):
"O(1)"
del self.store[key]
def __iter__(self):
return iter(self.store)
def __len__(self):
return len(self.store)
def sweep(self):
"O(m)"
now = time.time()
c = 0
while len(self.last_visits) > 0:
least = self.last_visits[0]
if now - least <= self.timeout:
break
for key in self.time_to_keys[least]:
heapq.heappop(self.last_visits)
if self.store.__contains__(key):
value = self.store[key]
if hasattr(value, 'close'):
value.close()
del self.store[key]
c += 1
del self.time_to_keys[least]
if c:
logging.debug('%d keys swept' % c)

View file

@ -66,12 +66,15 @@
# `server` means the UDP server that handles user requests # `server` means the UDP server that handles user requests
import time
import threading import threading
import socket import socket
import logging import logging
import struct import struct
import encrypt import encrypt
import eventloop import eventloop
import lru_cache
BUF_SIZE = 65536 BUF_SIZE = 65536
@ -131,8 +134,8 @@ class UDPRelay(object):
self._timeout = timeout self._timeout = timeout
self._is_local = is_local self._is_local = is_local
self._eventloop = eventloop.EventLoop() self._eventloop = eventloop.EventLoop()
self._cache = {} # TODO replace ith an LRU cache self._cache = lru_cache.LRUCache(timeout=timeout)
self._client_fd_to_server_addr = {} # TODO replace ith an LRU cache self._client_fd_to_server_addr = lru_cache.LRUCache(timeout=timeout)
def _handle_server(self): def _handle_server(self):
server = self._server_socket server = self._server_socket
@ -223,13 +226,20 @@ class UDPRelay(object):
def _run(self): def _run(self):
server_socket = self._server_socket server_socket = self._server_socket
self._eventloop.add(server_socket, eventloop.MODE_IN) self._eventloop.add(server_socket, eventloop.MODE_IN)
last_time = time.time()
while True: while True:
events = self._eventloop.poll() events = self._eventloop.poll(10)
for sock, event in events: for sock, event in events:
if sock == self._server_socket: if sock == self._server_socket:
self._handle_server() self._handle_server()
else: else:
self._handle_client(sock) self._handle_client(sock)
now = time.time()
if now - last_time > 3.5:
self._cache.sweep()
if now - last_time > 7:
self._client_fd_to_server_addr.sweep()
last_time = now
def start(self): def start(self):
addrs = socket.getaddrinfo(self._listen_addr, self._listen_port, 0, addrs = socket.getaddrinfo(self._listen_addr, self._listen_port, 0,