Swift源码分析----swift-proxy与swift-account(1)

感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!

如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn

PS:最近没有登录博客,很多朋友的留言没有看见,这里道歉!还有就是本人较少上QQ,可以邮件交流。


概述:

    上一篇博客中我们说过,请求信息到达swift-proxy服务之后,会确定获取具体的控制器(ObjectController、ContainerController、AccountController),接下来就是调用/swift/proxy/controllers/account.py或/swift/proxy/controllers/container.py或/swift/proxy/controllers/obj.py下面的PUT,POST,DELETE,GET,HEAD等方法;然后再在具体的方法中实现到具体存储服务(Object-server、Container-server、Account-server)的连接,继而调用其下具体的PUT,POST,DELETE,GET,HEAD等方法来进行请求req的实现;

这篇博客主要关注swift-proxy与swift-account服务中PUT,POST,DELETE,GET,HEAD等方法的对应调用实现;


源码解析部分(代码中较重要的部分已经进行了相关的注释):


GETorHEAD

/swift/proxy/controllers/account.py----class AccountController(Controller)----def GETorHEAD

def GETorHEAD(self, req):
    """
    通过HTTP处理GET/HEAD请求;
    """
    if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
        resp = HTTPBadRequest(request=req)
        resp.body = 'Account name length of %d longer than %d' % (len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
        return resp

    # get_nodes:为object获取分区号和所有副本节点信息;
    partition, nodes = self.app.account_ring.get_nodes(self.account_name)
        
    # GETorHEAD_base:HTTP GET或HEAD的基本处理;
    # 返回swob.Response对象;
    resp = self.GETorHEAD_base(
        req, _('Account'), self.app.account_ring, partition,
        req.swift_entity_path.rstrip('/'))
        
        if resp.status_int == HTTP_NOT_FOUND:
            if resp.headers.get('X-Account-Status', '').lower() == 'deleted':
                resp.status = HTTP_GONE
            elif self.app.account_autocreate:
                resp = account_listing_response(self.account_name, req,
                                                get_listing_content_type(req))
        if req.environ.get('swift_owner'):
            self.add_acls_from_sys_metadata(resp)
        else:
            for header in self.app.swift_owner_headers:
                resp.headers.pop(header, None)
        return resp
1.为object获取分区号和所有副本节点信息;
2.HTTP GET或HEAD的基本处理,实现发送请求到远程对象服务上并调用具体方法来处理请求信息;
  注:这里的具体实现就不详细解析了;


/swift/account/server.py----class AccountController(object)----def HEAD

def HEAD(self, req):
    """
    处理HTTP协议的HEAD请求;     
    HEAD请求返回account的基本信息,并以key-value的形式保存在HTTPHEAD中返回;
    """
    drive, part, account = split_and_validate_path(req, 3)
    out_content_type = get_listing_content_type(req)
        
    # mount_check是是否进行mount检查;
    # 如果进行mount检查,并且检查结果没有挂载,则引发http 507错误,提示磁盘没有足够存储空间;
    if self.mount_check and not check_mount(self.root, drive):
        return HTTPInsufficientStorage(drive=drive, request=req)
        
    # _get_account_broker是一个内部方法,功能是返回一个AccountBroker的实例,用于代理对sqlite数据库的操作;
    broker = self._get_account_broker(drive, part, account,
                                          pending_timeout=0.1,
                                          stale_reads_ok=True)
        
    if broker.is_deleted():
        return self._deleted_response(broker, req, HTTPNotFound)
        
    # get_info:为账户获取全局数据,获得account的基本信息;
    # 返回包括account, created_at, put_timestamp, delete_timestamp, container_count, object_count, bytes_used, hash, id等值的字典;
    info = broker.get_info()
    headers = {
            'X-Account-Container-Count': info['container_count'],
            'X-Account-Object-Count': info['object_count'],
            'X-Account-Bytes-Used': info['bytes_used'],
            'X-Timestamp': info['created_at'],
            'X-PUT-Timestamp': info['put_timestamp']}
    headers.update((key, value)
                   for key, (value, timestamp) in
                   broker.metadata.iteritems() if value != '')
    headers['Content-Type'] = out_content_type
        
        return HTTPNoContent(request=req, headers=headers, charset='utf-8')
注:HEAD请求返回account的基本信息(元数据信息),并以key-value的形式保存在HTTPHEAD中返回;


/swift/account/server.py----class AccountController(object)----def GET

def GET(self, req):
    """
    处理HTTP协议的GET请求;
    GET同HEAD一样,都是请求返回account的基本信息,并以key-value的形式保存在HTTPHEAD当中;
    不同之处在于GET方法中获取了指定account下的container列表,存储在body中,同HTTPHEAD一同返回;
    """
    drive, part, account = split_and_validate_path(req, 3)
    prefix = get_param(req, 'prefix')
    delimiter = get_param(req, 'delimiter')
    if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254):
        # delimiters can be made more flexible later
        return HTTPPreconditionFailed(body='Bad delimiter')
    limit = ACCOUNT_LISTING_LIMIT
    given_limit = get_param(req, 'limit')
    if given_limit and given_limit.isdigit():
        limit = int(given_limit)
        if limit > ACCOUNT_LISTING_LIMIT:
            return HTTPPreconditionFailed(request=req, body='Maximum limit is %d' % ACCOUNT_LISTING_LIMIT)
    marker = get_param(req, 'marker', '')
    end_marker = get_param(req, 'end_marker')
    out_content_type = get_listing_content_type(req)

    # mount_check是是否进行mount检查;
    # 如果进行mount检查,并且检查结果没有挂载,则引发http 507错误,提示磁盘没有足够存储空间;
    if self.mount_check and not check_mount(self.root, drive):
        return HTTPInsufficientStorage(drive=drive, request=req)
        
    # _get_account_broker是一个内部方法,功能是返回一个AccountBroker的实例,用于代理对sqlite数据库的操作;
    broker = self._get_account_broker(drive, part, account,
                                          pending_timeout=0.1,
                                          stale_reads_ok=True)
        
    if broker.is_deleted():
        return self._deleted_response(broker, req, HTTPNotFound)
        
    # 获取指定account下的容器列表(包括具体容器的相关信息);
    return account_listing_response(account, req, out_content_type, broker,
                                    limit, marker, end_marker, prefix,
                                    delimiter)

来看方法account_listing_response的具体实现:

def account_listing_response(account, req, response_content_type, broker=None,
                             limit='', marker='', end_marker='', prefix='',
                             delimiter=''):
    """
    获取指定account下的容器列表(包括具体容器的相关信息);
    """
    if broker is None:
        broker = FakeAccountBroker()

    info = broker.get_info()
    resp_headers = {
        'X-Account-Container-Count': info['container_count'],
        'X-Account-Object-Count': info['object_count'],
        'X-Account-Bytes-Used': info['bytes_used'],
        'X-Timestamp': info['created_at'],
        'X-PUT-Timestamp': info['put_timestamp']}
    resp_headers.update((key, value)
                        for key, (value, timestamp) in
                        broker.metadata.iteritems() if value != '')

    # 获取容器列表,每个容器信息包括(name, object_count, bytes_used, 0);
    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret

下一篇博客将继续swift-proxy与swift-account的分析工作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值