memcached python客户端编写实践
生活随笔
收集整理的這篇文章主要介紹了
memcached python客户端编写实践
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
Memcached Python Client
本小菜剛學完python,想寫點小東西練練手,然后看到memcached這個東東熟悉了下,感覺自己還能實現一點基本的功能(對于memcached這種分布式靠客戶端來實現的神器,一些最重要的功能我都是還沒有實現的。。。這個。。。),于是寫了如下拙劣的代碼,請各位大牛拍磚。。。
#!/usr/bin/env python''' This is a fake memcached client.Overview ======== Cachedog use python native socket APIs to access memcached server. It is inspired by python-memcached. This stuff is aim to be familiar with Python language, for the author is a beginner for python.Commands ======== Standard Protocol:command <key> <flags> <expiration time> <bytes><value>The "standard protocol stuff" of memcached involves running a command against an "item". An item consists of:1. A key (arbitrary string up to 250 bytes in length. No space or newlines for ASCII mode) 2. A 32bit "flag" value 3. An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a unixtimestamp of an exact date. 4. A 64bit "CAS" value, which is kept unique. 5. Arbitrary dataCAS is optional (can be disabled entirely with -C, and there are more fields that internally make up an item, but these are what your client interacts with.Full command list can be found here: https://code.google.com/p/memcached/wiki/NewCommandsUsage summary ============= You must know it... :)TODO ==== add compress add log add multi-serversRelease note ============ 0.1.0 Can access ONLY one server Basic memcached command supported Can log command history ''' import os import sys import time import socket import logging# try: # import cPickle as pickle # except ImportError: # import pickle#from binascii import crc32# try: # from threading import local # except ImportError: # class local(): # pass__author__ = 'xishvai <xishvai@gmail.com>' __version__ = '0.1.0' __license__ = 'Python Software Foundation License'SERVER_MAX_KEY_LENGTH = 250 # ordinary value # assume not larger than 1M, you can change it as you need. SERVER_MAX_VALUE_LENGTH = 1024 * 1024MAX_DATA_LENGTH = 1024 * 1024LOCALHOST = '127.0.0.1' DEFAULT_PORT = 11211 DEFAULT_ADDRESS = (LOCALHOST, DEFAULT_PORT)class Noreply:passclass Client:def __init__(self, url):self.url = urlself.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.cmdlog = []self.cmd = Nonetry:a_url, a_port = self.url.split(':')addr = (a_url, int(a_port))self.sock.connect(addr)except socket.error, msg:print('Connecting %s error' % msg[1])sys.exit(1)## constants & exception & tools#_FLAG_INTEGER = 1 << 0_FLAG_LONG = 1 << 1_FLAG_PICKLE = 1 << 2_FLAG_COMPRESS = 1 << 3class MemcachedKeyError(Exception):passclass MemcachedKeyNoneError(MemcachedKeyError):passclass MemcachedKeyTypeError(MemcachedKeyError):passclass MemcachedKeyLengthError(MemcachedKeyError):passclass MemcachedKeyCharacterError(MemcachedKeyError):passclass MemcachedStringEncodingError(MemcachedKeyError):pass## Storage Commands: (set,add,replace,append,prepend,cas)#def set(self, key, value, flags=0, expired=0):'''Most common command. Store this data, possibly overwriting any existing data.New items are at the top of the LRU.'''self.cmd = '%s %s %d %d %d\r\n%s\r\n' % ('set', key, flags, expired, len(value), value)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef add(self, key, value, flags=0, expired=0):'''Store this data, only if it does not already exist. New items are at the top ofthe LRU. If an item already exists and an add fails, it promotes the item to thefront of the LRU anyway.'''self.cmd = '%s %s %d %d %d\r\n%s\r\n' % ('add', key, flags, expired, len(value), value)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef replace(self, key, value, flags=0, expired=0):'''Store this data, but only if the data already exists. Almost never used,and exists for protocol completeness (set, add, replace, etc)'''self.cmd = '%s %s %d %d %d\r\n%s\r\n' % ('replace', key, flags, expired, len(value), value)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef append(self, key, value, flags=0, expired=0):'''Add this data after the last byte in an existing item. This does not allowyou to extend past the item limit. Useful for managing lists.'''self.cmd = '%s %s %d %d %d\r\n%s\r\n' % ('append', key, flags, expired, len(value), value)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef prepend(self, key, value, flsgs=0, expired=0):'''Same as append, but adding new data before existing data.'''self.cmd = '%s %s %d %d %d\r\n%s\r\n' % ('prepend', key, flags, expired, len(value), value)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef cas(self, key, value, flags=0, expired=0, cas_value=0):'''Check And Set (or Compare And Swap). An operation that stores data, but only ifno one else has updated the data since you read it last. Useful for resolving raceconditions on updating cache data.'''self.cmd = '%s %s %d %d %d %d\r\n%s\r\n' % ('cas', key, flags, expired, cas_value, len(value), value)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return data## Retrieval Commands: (get,gets,delete,incr/decr)#def get(self, key):'''Command for retrieving data. Takes one or more keys and returns all found items.'''self.cmd = '%s %s\r\n' % ('get', key)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef gets(self,key):'''An alternative get command for using with CAS. Returns a CAS identifier(a unique 64bit number) with the item. Return this value with the cas command.If the item's CAS value has changed since you gets'ed it, it will not be stored.'''self.cmd = '%s %s\r\n' % ('gets', key)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return data def delete(self, key):'''Removes an item from the cache, if it exists.'''self.cmd = '%s %s\r\n' % ('delete', key)self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef incr(self, key):'''Increment and Decrement. If an item stored is the string representation of a 64bitinteger, you may run incr or decr commands to modify that number. You may only incrby positive values, or decr by positive values. They does not accept negative values.If a value does not already exist, incr/decr will fail.'''passdef decr(self, key):'''Increment and Decrement. If an item stored is the string representation of a 64bitinteger, you may run incr or decr commands to modify that number. You may only incrby positive values, or decr by positive values. They does not accept negative values.If a value does not already exist, incr/decr will fail.'''pass## Statistics: (stats,stats items,stats slabs,stats sizes,flush_all)#def stats(self):'''ye 'ole basic stats command.'''self.cmd = '%s\r\n' % 'stats'self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef stats_items(self):'''Returns some information, broken down by slab, about items stored in memcached.'''self.cmd = '%s\r\n' % 'stats items'self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef stats_slabs(self):'''Returns more information, broken down by slab, about items stored in memcached.More centered to performance of a slab rather than counts of particular items.'''self.cmd = '%s\r\n' % 'stats slabs'self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef stats_sizes(self):'''A special command that shows you how items would be distributed if slabs were brokeninto 32byte buckets instead of your current number of slabs. Useful for determininghow efficient your slab sizing is.WARNING this is a development command. As of 1.4 it is still the only command whichwill lock your memcached instance for some time. If you have many millions of storeditems, it can become unresponsive for several minutes. Run this at your own risk. Itis roadmapped to either make this feature optional or at least speed it up.'''self.cmd = '%s\r\n' % 'stats sizes'self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef flush_all(self):# flush_all([timeout])# lazy delete'''Invalidate all existing cache items. Optionally takes a parameter, which means to invalidateall items after N seconds have passed.This command does not pause the server, as it returns immediately. It does not free up orflush memory at all, it just causes all items to expire.'''self.cmd = '%s\r\n' % 'flush_all'self.cmdlog.append(self.cmd)self.sock.sendall(self.cmd.encode())data = self.sock.recv(MAX_DATA_LENGTH)return datadef stats_reset(self):pass# stats cachedump slab_id limit_numif __name__ == '__main__':mc = Client('127.0.0.1:11211')mc.set('xs', 'xishvai')mc.set('yj', 'yangjun')data = mc.get('xs')print('get xs = ', data)data1 = mc.get('yj')print('get yj = ', data1)mc.replace('yj', 'youngsmart')print('get yj = ', mc.get('yj'))mc.add('xs', 'xishvai') # NOT_STOREDmc.delete('yj')mc.get('yj')mc.flush_all()print('get xs = ', mc.get('xs'))# for s in mc.cmdlog:# print(s, ' ')# print('stats = ', mc.stats())# print('stats items= ', mc.stats_items())# print('stats slabs= ', mc.stats_slabs())# print('stats sizes= ', mc.stats_sizes())
轉載于:https://my.oschina.net/xishvaigo/blog/180377
總結
以上是生活随笔為你收集整理的memcached python客户端编写实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: velocity 模板语言(VTL)
- 下一篇: 如何通过IP定位交换机