swift源码详解(三)——proxy/controllers/base.py
回swift代码结构目录
update_headers
1 | def update_headers(response, headers): |
- 更新response的header。
- 查看headers中是否’items’属性,有的话给headers赋值。
- 遍历headers中的每个header,如果是’etag’,则去除值中的双引号,并写到response的header中,如果header不是特殊的header,则写到response的header中。
source_key
1 | def source_key(resp): |
- 依次获取response中的header’x-put-timestamp’和’x-timestamp’的值,如果有值则返回,没有则返回0。
delay_denial
1 | def delay_denial(func): |
- 方法标签,标识了该标签的方法表示与swift.authorize有关,会延迟认证。
get_account_memcache_key
1 | def get_account_memcache_key(account): |
- 获取account的缓存key。
get_container_memcache_key
1 | def get_container_memcache_key(account, container): |
- 获取container的缓存key。
_prep_headers_to_info
1 | def _prep_headers_to_info(headers, server_type): |
- 将header根据server_type进行分类,以x--meta开头的为用户信息类,以x--sysmeta开头的为系统信息类,其他的为other类。
headers_to_account_info
1 | def headers_to_account_info(headers, status_int=HTTP_OK): |
- 将account的header进行分类,返回包含account信息的字典。
headers_to_container_info
1 | def headers_to_container_info(headers, status_int=HTTP_OK): |
- 将container的header进行分类,返回包含container信息的字典。
headers_to_object_info
1 | def headers_to_object_info(headers, status_int=HTTP_OK): |
- 将object的header进行分类,返回包含object信息的字典。
cors_validation
1 | def cors_validation(func): |
- 方法标签,对CORS请求进行验证。
- 先判断该请求是否是一个跨域资源共享(CORS)请求,是的话先获取container的信息,再根据container信息获取cors信息。
- 如果controller的cors mode存在就判断原请求是否被允许,允许的话返回response。
1 | # Expose, |
- 方法标签,对CORS请求进行验证。
- 先判断该请求是否是一个跨域资源共享(CORS)请求,是的话先获取container的信息,再根据container信息获取cors信息。
- 根据controller的cors mode判断cors请求是否被允许,是的话返回response。
1 | # The user agent won't process the response if the Allow-Origin |
- 如果response里面不包含’Access-Control-Allow-Origin’ header,则加上该header。
get_object_info
1 | def get_object_info(env, app, path=None, swift_source=None): |
- 根据env和app获取object的结构信息。
get_container_info
1 | def get_container_info(env, app, swift_source=None): |
- 根据env和app获取container的结构信息。
get_account_info
1 | def get_account_info(env, app, swift_source=None): |
- 根据env和app获取account的结构信息。
_get_cache_key
1 | def _get_cache_key(account, container): |
- 获取account和container的缓存key,account是’account/account名’,container是’container/account名/container名’,还有env_key,值为’swift.缓存key’。
get_object_env_key
1 | def get_object_env_key(account, container, obj): |
- 得到object的env_key,值为’swift.object/account名/container名/object名。
set_info_cache
1 | def _set_info_cache(app, env, account, container, resp): |
- 信息在缓存和env都各存一份,缓存一般用来避免对account和container没必要的调用,这是一个私有方法,主要被GETorHEAD_base和clear_info_cache方法调用。如果想通过HEAD和GET获取container/account信息,建议使用GETorHEAD_base方法,因为该方法会设置缓存信息。
- 检查container和account是否存在,再通过account和container获取缓存key。
- 根据response状态码设置缓存时间,如果缓存时间设置为None,则在env和缓存中移除cache_key缓存信息。
- 最后在缓存和env中设置container或account的info信息。
_set_object_info_cache
1 | def _set_object_info_cache(app, env, account, container, obj, resp): |
- object的信息只缓存在env中,没有缓存在memcache中是因为缓存起来的话会对缓存造成压力,这是前一次请求的缓存。缓存为了避免那些对object没必要的调用,这是一个私有方法,主要被GETorHEAD_base和clear_info_cache方法调用。如果想通过HEAD和GET获取container/account信息,建议使用GETorHEAD_base方法,因为该方法会设置缓存信息。
- 先获取object的env_key,如果response没有则在env中移除env_key的信息,最后在env中添加object的info信息。
clear_info_cache
1 | def clear_info_cache(app, env, account, container=None): |
- 在memcache和env中清除account或container的缓存信息。
_get_info_cache
1 | def _get_info_cache(app, env, account, container=None): |
- 私有方法,被get_info调用,在env和memcache中获取account和container信息,顺序是先env再memcache。
- 获取env_key和cache_keyi,如果env_key在env中存在,则返回env中的值。
- 如果env中没有,再从memcache中获取信息,将获取到的信息放到env中。
_prepare_pre_auth_info_request
1 | def _prepare_pre_auth_info_request(env, path, swift_source): |
- 准备一个做过认证的HEAD请求来获取信息。
get_info
1 | def get_info(app, env, account, container=None, ret_not_found=False, |
- 从缓存中获取info信息,如果缓存中有且状态是success,则返回info。如果缓存没有,则发起1个不用认证的请求获取account和container的info信息。
_get_object_info
1 | def _get_object_info(app, env, account, container, obj, swift_source=None): |
- 先从env中获取object的info信息,如果没有则发起请求不认证的请求重新获取。
close_swift_conn
1 | def close_swift_conn(src): |
- 关闭swift连接,用了很底层的一个关闭socket连接的方法。
GetOrHeadHandler类
init方法
1 | def __init__(self, app, req, server_type, ring, partition, path, |
- GetOrHeadHandler类的初始化方法。
fast_forward
1 | def fast_forward(self, num_bytes): |
- 先判断Range是否在后台进程的header中,如果没有,则在后台进程header中增加Range,值为’bytes=’加num_bytes。
- 如果有,先创建一个Range对象,判断如果Range对象的ranges如果大于1,则报NotImplementedError的异常。
- 从rangs中取到开始和结束字节数,先检查两个字节数是否正确,不正确抛异常,正确的话将其重新放入到后台进程header中。
is_good_source
1 | def is_good_source(self, src): |
- 如果是一个Object请求,并且返回状态码是416,则返回True,否则返回状态码是否200~399。
_make_app_iter
1 | def _make_app_iter(self, req, node, source): |
- 初始化本地变量,如果是object请求,则将节点超时时间设置为object的recoverable_node_timeout。
1 | while True: |
- 通过一个无限循环,不断读取response的数据,累加读取的块数大小和字节总长度。
- 如果读取数据超时,则处理异常,如果请求不是Object则抛出最近的异常信息。
- 记录已读的字节范围,错误抛异常。
- 获取新的source和节点,如果source存在的话,则创建一个异常并关闭连接重新初始化,否则抛出异常。
- 如果读取不到数据,则跳出循环。
1 | # This is for fairness; if the network is outpacing the CPU, |
- 每读取5个字节块,休眠一次。
- 读取数据超时抛异常。
- 写入数据超时记日志。
- 抛出各种异常后关闭连接。
_get_source_and_node
1 | def _get_source_and_node(self): |
- 初始化本地变量,设置node_timeout时间。
1 | for node in self.app.iter_nodes(self.ring, self.partition): |
- 循环取节点,如果节点已经被使用了,则跳过该节点,否则封装http连接,设置节点时间。
- 获取请求结果,如果超时,则抛异常,跳出此次循环。
1 | if self.is_good_source(possible_source): |
- 如果返回结果合理,则判断返回结果中的PUT时间是否存在,不存在证明还没有同步,则返回404并关闭连接。
- 如果时间存在,则继续判断已用etag是否存在,存在的话从返回结果中取出etag值与之比较,不相等就返回404并关闭连接。
- 已用etag不存在,则将返回结果设置到自身属性中,并判断是否最新,是则跳出循环,取一个good source就足够了。
1 | else: |
- 如果返回结果不是一个good source,则将返回结果信息设置到自身属性,如果返回状态是507,则将节点加入到错误列表,如果返回状态是其他500以上的数字,则抛出异常。
- 循环结束后,如果取到了source,则先将sources进行排序然后取第一个,接着关闭剩下的source。
- 添加节点到已用节点,设置易用etag,返回结果,如果取不到source,则返回空。
get_working_response
1 | def get_working_response(self, req): |
- 先获取source和node,如果有的话,则根据req参数封装response,如果请求是’GET’并且source的状态是200或206,则设置response的app_iter和conn。
- 将source的状态码和header设置进response,再分别根据source的内容设置返回的response的值。
Controller类
init方法
1 | """Base WSGI controller class for the proxy""" |
- 设置类型为base,初始化方法,创建controller时使用。
allowed_methods
1 |
|
- 类属性变量allowed_methods的初始化方法。
transfer_headers
1 | def transfer_headers(self, src_headers, dst_headers): |
- 将一个原始客户端请求的遗留header转换为新的header,给后台进程使用。
transfer_headers
1 | def generate_request_headers(self, orig_req=None, additional=None, |
- 生成一组headers为后台进程使用。
account_info
1 | def account_info(self, account, req=None): |
- 获取account信息,正常返回分区号,节点和容器数量,获取不到返回3个None。
account_info
1 | def container_info(self, account, container, req=None): |
- 获取container信息,会顺便校验container是否存在,也会校验account是否存在。
make_request(私有方法)
1 | def _make_request(self, nodes, part, method, path, headers, query, |
- 遍历每个节点,根据节点信息发起请求,如果请求不是100+和500+,则返回请求结果。
- 如果请求状态码为507,则加入node到异常node列表。
- 其他异常抛出异常信息。
make_requests
1 | def make_requests(self, req, ring, part, method, path, headers, |
- 先通过partition获取node节点,再根据节点个数创建线程发起每个节点请求。
- 获取每个线程的返回结果,将状态码和响应结果记录保存到列表中,如果状态码列表个数超过节点的一半,则跳出循环。
- 将剩下的response设置为503,最后通过best_response方法获取response。
have_quorum
1 | def have_quorum(self, statuses, node_count): |
- 通过节点个数和一组状态码判断响应是否已经满足限额。
best_response
1 | def best_response(self, req, statuses, reasons, bodies, server_type, |
- 给定一组response,返回最佳的response。
- 比如副本数是3,response列表是[201,201,503],则返回201。
autocreate_account
1 | def autocreate_account(self, env, account): |
- 发起一个PUT请求自动创建account,创建失败记录警告信息。
GETorHEAD_base
1 | def GETorHEAD_base(self, req, server_type, ring, partition, path): |
- 基类controller的get或head请求处理方法,首先构造header和handler发起一个http请求。
- 如果请求没有响应,则调用best_response方法取到response。
- 如果请求有响应,则根据request分割出account、container和object信息,设置到缓存中,最后返回response。
is_origin_allowed
1 | def is_origin_allowed(self, cors_info, origin): |
- 判断该请求方法是否允许发起请求,先从header中获取’allow_origin’的值,如果有的花,更新允许访问列表。
- 如果原请求方法在允许访问列表中,或者允许访问列表中有’*’,则返回True。
OPTIONS
1 |
|
- options请求的基本handler,准备一个默认的response,如果不是一个CORS请求,则返回默认的response。
1 | # This is a CORS preflight request so check it's allowed |
- 如果对account进行操作的CORS请求,则返回默认reponse,否则获取container信息。
- 如果CORS请求不允许,则返回401。
1 | # Allow all headers requested in the request. The CORS |
- 在response的header中增加相关header,分别有’access-control-allow-origin’,’access-control-max-age’,’access-control-allow-methods’和’access-control-allow-headers’。