swift存储_swift存储 后端 - CSDN
  • swift 对象存储

    2019-04-25 19:09:11
    有没有研究swift对象存储大神,一起讨论相互进步qq:89666173

      有没有研究swift对象存储大神,一起讨论相互进步qq:89666173

    展开全文
  • swift本地存储

    千次阅读 2017-09-01 09:09:55
    前言:在我们开发过程中,不管是你做啥子应用,都要遇到数据的保存问题。将数据保存本地,这样让程序的运行更加...文件操作知识临时充饥看我上篇文章:Swift文件管理必知的一些操作 1.使用NSUserDefaults存储数据 NSUse

    前言:在我们开发过程中,不管是你做啥子应用,都要遇到数据的保存问题。将数据保存本地,这样让程序的运行更加流畅,不在出现小菊❀这样的╮(╯﹏╰)╭东东了,使得用户体验更好! 以下将介绍NSUserDefaults/ NSKeyedArchiver/ write写入方式.

    文件操作知识临时充饥看我上篇文章:Swift文件管理必知的一些操作

    1.使用NSUserDefaults存储数据

    NSUserDefaults:一般我们拿它用来保存应用程序设置和属性、用户保存的数据,用户的手机不管是关机or开机时候都会保存在本地(除非你把他删除了),它一般可以存储类型包括:字符,数组,字典,NSData,NSNumber以及基本数据类型都可.那就来看看咋的实现它吧!
    这里我简单的对其简单封装了一下方法,我就直接贴代码了,重要位置我都加了注释(ps:想看比较全面的可以参考这篇文章Swift之一步一步带你封装一个本地缓存库):

        /*  使用NSUserDefaults对普通数据对象储存   */
    
        /**
         储存
    
         - parameter key:   key
         - parameter value: value
         */
        class func setNormalDefault(key:String, value:AnyObject?){
            if value == nil {
                NSUserDefaults.standardUserDefaults().removeObjectForKey(key)
            }
            else{
                NSUserDefaults.standardUserDefaults().setObject(value, forKey: key)
                // 同步
                NSUserDefaults.standardUserDefaults().synchronize()
            }
        }
    
        /**
         通过对应的key移除储存
    
         - parameter key: 对应key
         */
        class func removeNormalUserDefault(key:String?){
            if key != nil {
                NSUserDefaults.standardUserDefaults().removeObjectForKey(key!)
                NSUserDefaults.standardUserDefaults().synchronize()
            }
        }
    
        /**
         通过key找到储存的value
    
         - parameter key: key
    
         - returns: AnyObject
         */
        class func getNormalDefult(key:String)->AnyObject?{
            return NSUserDefaults.standardUserDefaults().valueForKey(key)
        }

    下面举个简单 looklook

    private func userDefaultStoreData(){
            Tool.setNormalDefault("name", value: "Rookie")
            let value = Tool.getNormalDefult("name")
            print("测试NSUserDefaults 简单对象储存\\(value)")
        }
    
    //   控制台输出: **测试****NSUserDefaults ****简单对象储存****Optional(Rookie)**

    2.通过write写入方式存储为plist属性列表
    write写入方式也是一种把数据永久保存在磁盘中储存方式,一般步骤:1)获取路径(一般有两种方式:使用NSSearchPathForDirectoriesInDomains或URLsForDirectory;使用NSHomeDirectory➕相应的路径);2)向文件中写入数据;3)从文件中读取数据. 具体代码如下:

        /**
         创建文件
    
         - parameter name:        文件名
         - parameter fileBaseUrl: url
    
         - returns: 文件路径
         */
       class func creatNewFiles(name:String, fileBaseUrl:NSURL) -> String{
            let manager = NSFileManager.defaultManager()
            let file = fileBaseUrl.URLByAppendingPathComponent(name)
    
            let exist = manager.fileExistsAtPath(file.path!)
            if !exist {
                let createFilesSuccess = manager.createFileAtPath(file.path!, contents: nil, attributes: nil)
                print("文件创建结果: \\(createFilesSuccess)")
            }
            return String(file)
        }
    
        /**
         读取文件
    
         - parameter name:        文件名
         - parameter fileBaseUrl: url
    
         - returns: 读取数据
         */
        class func readTheFlies(name:String , fileBaseUrl:NSURL) ->NSString{
            let file = fileBaseUrl.URLByAppendingPathComponent(name)
           //  print(file)
            let readHandler = try! NSFileHandle(forReadingFromURL:file)
            let data = readHandler.readDataToEndOfFile()
            let readString = NSString(data: data, encoding: NSUTF8StringEncoding)
            return readString!
        }

    实现 如下:

    // MARK:-  存储plist属性列表
        private func savePlistFiles(){
            // 储存的沙盒路径
            let manager = NSFileManager.defaultManager()
            let urlForCatch = manager.URLsForDirectory(NSSearchPathDirectory.CachesDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask)
            let url = urlForCatch.first! as NSURL
            let fileName = "RookieSon.plist"
            // 创建文件
            let filesPath = Tool.creatNewFiles(fileName, fileBaseUrl: url)
            // 储存数据
            let saveDataInfo = NSMutableArray()
            saveDataInfo.addObject("我的剑,就是你的剑")
            saveDataInfo.addObject("我用双手成就你的梦想")
            saveDataInfo.addObject("纵然前路迷茫,纵然天隔一方,纵然我手中的刀刃已然破碎,也无法阻挡我寻找你的道路")
            //        print(saveDataInfo)
            // 写入文件
            saveDataInfo.writeToURL(NSURL(string: filesPath)!, atomically: true)
    
            // 读取文件
            let readDataInfo = Tool.readTheFlies(fileName, fileBaseUrl: url)
            print(readDataInfo)
        }
    
    /* 打印结果: 
    **<plist version="1.0">**
    **<array>**
    ** <string>****我的剑****,****就是你的剑****</string>**
    ** <string>****我用双手成就你的梦想****</string>**
    ** <string>****纵然前路迷茫,纵然天隔一方,纵然我手中的刀刃已然破碎,也无法阻挡我寻找你的道路****</string>**
    **</array>**
    **</plist>**
    */

    3.NSKeyedArchiver采用归档的形式来保存数据
    NSKeyedArchiver保存数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法,简单的说就是告诉系统怎么对对象进行编码,怎么对对象进行解码. 下面就对Person这个对象进行归档保存:
    Person.m文件:

    class Person: NSObject {
    
        var name:String?
        var phone:String?
    
        // 构造方法
        init(name:String!,phone:String!) {
            self.name = name
            self.phone = phone
    
            super.init()
        }
    
        // 从NSObject解析回来
    
        init(coder aDecoder:NSCoder!){
            self.name=aDecoder.decodeObjectForKey("name") as? String
            self.phone=aDecoder.decodeObjectForKey("phone") as? String
        }
    
        //编码成object,哪些属性需要归档,怎么归档
        func encodeWithCoder(aCoder:NSCoder!){
            aCoder.encodeObject(name,forKey:"name")
            aCoder.encodeObject(phone,forKey:"phone")
        }
    
    }

    实现部分代码如下:

     private func  archiveSaveDataInfo(){
        // 储存自定义对象
        let userDefault = NSUserDefaults.standardUserDefaults()
        let mo = Person(name: "RookieYX", phone: "123456")
        // 实例对象转化成NSData
        let moData:NSData = NSKeyedArchiver.archivedDataWithRootObject(mo)
        // 储存NSData对象
        userDefault.setObject(moData, forKey: "myMo")
        // 自定义对象读取
        let myMoData = userDefault.objectForKey("myMo") as! NSData
        // 解档
        let myM= NSKeyedUnarchiver.unarchiveObjectWithData(myMoData) as! Person
        print(myM)
    
        }
    
    /*
    打印结果:
    **<SwiftUserDefault.Person: 0x7fd958518450>**
    **person ****名字****: Optional("Rookie")**
    **person ****电话****: Optional("123456")**
    */

    看了以上写的东西,我相信你已经对这三种简单的存储有了初步理解,那么我们就来检查一下自己的学习的知识吧,我们现在做一个简单的网络图片的本地缓存处理. 你可以先想一下,在继续看下去吧(⊙o⊙)…!(具体我直接贴代码)
    函数实现部分:

        /**
         传递一个uiimageView,和图片路径,设置图片,异步操作
    
         - parameter newsImageView: UIImageView
         - parameter imageString:   网络图片地址
         */
       class func setImagesViewData(newsImageView:UIImageView,imageString:String){
            // 获取文件路径
            var catePath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory,NSSearchPathDomainMask.AllDomainsMask, true)
            print(catePath)
            let cateImagesUrl:NSURL = NSURL(fileURLWithPath: "\\(catePath.first)/\\(imageString.Rookie_MD5())")//获取缓存加密后的路径
    
            //缓存存在直接加载
            if let cateReadData:NSData  = NSData(contentsOfURL: cateImagesUrl){
                newsImageView.image = UIImage(data: cateReadData);
            }
            else{
                newsImageView.image = UIImage(named: "load.jpg");//默认图片
                //这里我们做个异步处理,用来加载图片
                let session = NSURLSession.sharedSession();
                let task = session.dataTaskWithURL(NSURL(string: imageString)!, completionHandler: { (imageData:NSData?, resp:NSURLResponse?, error:NSError?) in
                    if let error = error {
                        print("连接网络失败1:\\(error)");
                    }else{
                        // 当我们加载完数据了回主线程修改图片
                        if let endImageData = imageData{
                            dispatch_sync(dispatch_get_main_queue(), {
                                newsImageView.image = UIImage(data: endImageData)
                            })
                            // 写入本地
                            endImageData.writeToURL(cateImagesUrl, atomically: true)
                        }
                    }
                })
    
                // 启动任务
                task.resume()
            }
        }

    实现部分代码:

     private func cacheIntenetImage(){
            Tool.setImagesViewData(ImgView, imageString: URL)
        }

    希望通过这篇文章可以对你有所帮助,因为我们在Swift学习之路上,如有错误之处,还请各位大 指出! ! 之后将会学习其他的数据存储方式,总结好之后也会更新在博客上, 有要学习的同学,可以关注一下me,可以通过这里互相学习一下,共同进步 ..



    作者:叫我干苦力的小码农
    链接:http://www.jianshu.com/p/efd358d53ffd
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    展开全文
  • Swift存储属性

    2017-01-08 20:56:45
    存储属性 /* 1、存储属性 2、常量存储属性 */ print("1、存储属性") class Person { let name:String = "zhang" var age:Int = 16 } //结构体常量对象,它本身是一个常量,其次对应的对象不可以被修改 //类...

    存储属性

    /*
     1、存储属性
     2、常量存储属性
     */
    print("1、存储属性")
    class Person {
        let name:String = "zhang"
        var age:Int = 16
    }
    //结构体常量对象,它本身是一个常量,其次对应的对象不可以被修改
    //类常量对象,它本身是一个常量,其次它对应的对象,可以通过它来进行修改
    //结构体或者枚举类型:值引用;类:引用
    let person = Person()//(name:"wang",age:16)
    //person.name = "wang"
    person.age = 18
    
    /*
     3、延迟存储属性
     Swift中所有的存储属性必须要有初始值,类以及结构体对象定义完之后,对象中所有的存储属性必须要有初始值,例外:延迟属性可以将属性的初始值化向后推迟到该属性第一次被调用时
     作用:
        (1)属性不适合一开始初始化
        (2)属性有可能从来不用,但是初始化又需要很长时间
     */
    print("\n3、延迟存储属性")
    struct MyStudent {
        var name:String
        var chinese:Double
        var math:Double
        func showStudent(){
            print("姓名:\(name),语文:\(chinese),数学:\(math)")
        }
    }
    
    class MyClass{
        var members:[MyStudent] = []
        //班级学生总成绩  lazy关键字延迟存储属性
        lazy var score:Double = self.getSorce()
        func getSorce() -> Double {
            print("lazy property")
            var sum :Double = 0
            for i in members {
                sum += i.chinese
                sum += i.math
            }
            if members.count > 0 {
                return sum / Double(members.count)
            }else{
                return 0
            }
        }
        func show(){
            for i in members {
                i.showStudent()
            }
        }
    }
    let s0 = MyStudent(name:"zhang",chinese:100,math:100)
    let s1 = MyStudent(name:"wang",chinese:90,math:90)
    
    let c0 = MyClass()
    c0.members.append(s0)
    c0.members.append(s1)
    c0.show()
    //print(c0.getSorce())
    print("======")
    print(c0.score)


    展开全文
  • Swift 存储目录

    千次阅读 2016-07-19 15:35:22
    在Storage node上运行着Linux系统并使用了XFS文件系统,逻辑上使用一致性哈希算法将固定总数的partition映射到每个Storage node上,每个Data也使用同样的哈希算法映射到Partition上,其层次结构如下图所示: ...
      在Storage node上运行着Linux系统并使用了XFS文件系统,逻辑上使用一致性哈希算法将固定总数的partition映射到每个Storage node上,每个Data也使用同样的哈希算法映射到Partition上,其层次结构如下图所示:

    Figure1:Stoage node hierachy 
      以我们的一台storage node sws51为例,该device的文件路径挂载到/srv/node/sdc,目录结构如下所示:

    root@sws51:/srv/node/sdc# ls

    accounts  async_pending  containers  objects  quarantined  tmp

      其中accountscontainersobjects分别是账号、容器、对象的存储目录,async_pending是异步待更新目录,quarantined是隔离目录,tmp是临时目录。

    1.objects目录

      在objects目录下存放的是各个partition目录,其中每个partition目录是由若干个suffix_path名的目录和一个hashes.pkl文件组成,suffix_path目录下是由objecthash_path名构成的目录,在hash_path目录下存放了关于object的数据和元数据,object存储目录的层次结构如图2所示。


    Figure2: Object directory hierachy 
    hashes.pkl是存放在每个partition中的一个2进制pickle化文件。例如:
    root@sws50:/srv/node/sdc/objects/100000# ls
    8bd  hashes.pkl
    In [1]: with open('hashes.pkl', 'rb') as fp:
       ...:     import pickle
       ...:     hashes = pickle.load(fp)
       ...:    
       ...:    
    In [2]: hashes
    Out[2]: {'8bd': '9e99c8eedaa3197a63f685dd92a5b4b8'}
    8bdsuffix_dir,而9e99c8eedaa3197a63f685dd92a5b4b8则是该partition下数据的md5哈希值。

    Object path生成过程
    object的存储路径由object server进程内部称为DiskFile类初始化时产生,过程如下:
    1.由文件所属的accountcontainerobject名称产生'/account/container/object'格式的字符串,和HASH_PATH_SUFFIX组成新的字符串,调用hash_path函数,生成md5 hashname_hash。其中HASH_PATH_SUFFIX作为salt来增加安全性,HASH_PATH_SUFFIX值存放在/etc/swift/swift.conf中。
    2. 调用storage_directory函数,传入DATADIR, partition, hash_path参数生成DATADIR/partition/name_path[-3:]/name_path格式字符串
    3. 连结path/devcie/storage_directory(DATADIR, partition,name_ hash)生成数据存储路径datadir
    4. 调用normalize_timestamp函数生成“16.5位”的时间戳+扩展名的格式生成对象名称

      例如,某object的存储路径为:/srv/node/sdc/objects/19892/ab1/136d0ab88371e25e16663fbd2ef42ab1/1320050752.09979.data
      其中每个目录分别表示:   

    Figure3: Object directory represention
    Object数据
      Object的数据存放在后缀为.data的文件中,它的metadata存放在以后缀为.meta的文件中,将被删除的Object以一个0字节后缀为.ts的文件存放。

    2.accounts目录
      在accounts目录下存放的是各个partition,而每个partition目录是由若干个suffix_path目录组成,suffix_path目录下是由accounthsh名构成的目录,在hsh目录下存放了关于accountsqlite dbaccount存储目录的层次结构如图4所示。

    Figure4: Account directory hierachy


    Account path生成过程
      account使用AccountController类来生成path,其过程与object类似,唯一的不同之处在于,accountdb命名调用hash_path(account)来生成,而不是使用时间戳的形式。例如,某accountdb存储路径为:/srv/node/sdc/accounts/20443/ac8/c7a5e0f94b23b79345b6036209f9cac8/ c7a5e0f94b23b79345b6036209f9cac8.db 


    Figure5: Object directory represention


    Account db数据
      在accountdb文件中,包含了account_statcontainerincoming_sync outgoing_sync 4张表。
      表account_stat是记录关于account的信息,如名称、创建时间、container数统计等等,其schema如下:
    CREATE TABLE account_stat (
                    account TEXT,
                    created_at TEXT,
                    put_timestamp TEXT DEFAULT '0',
                    delete_timestamp TEXT DEFAULT '0',
                    container_count INTEGER,
                    object_count INTEGER DEFAULT 0,
                    bytes_used INTEGER DEFAULT 0,
                    hash TEXT default '00000000000000000000000000000000',
                    id TEXT,
                    status TEXT DEFAULT '',
                    status_changed_at TEXT DEFAULT '0',
                    metadata TEXT DEFAULT ''
                );
      account表示account名称,created_at表示创建时间,put_timestamp表示put request的时间戳,delete_timestamp表示delete request的时间戳,container_countcountainer的计数,object_countobject的计数,bytes_used表示已使用的字节数,hash表示db文件的hash值,id表示统一标识符,status表示account是否被标记为删除,status_changed_at表示状态修改时间,metadata表示account的元数据。
    test账号为例,该db的表account_stat中存放了以下数据项:


      表container记录关于container的信息schema如下:
    CREATE TABLE container (
                    ROWID INTEGER PRIMARY KEY AUTOINCREMENT,
                    name TEXT,
                    put_timestamp TEXT,
                    delete_timestamp TEXT,
                    object_count INTEGER,
                    bytes_used INTEGER,
                    deleted INTEGER DEFAULT 0
                );
    CREATE INDEX ix_container_deleted_name ON
                    container (deleted, name);
    CREATE TRIGGER container_delete AFTER DELETE ON container
                BEGIN
                    UPDATE account_stat
                    SET container_count = container_count - (1 - old.deleted),
                        object_count = object_count - old.object_count,
                        bytes_used = bytes_used - old.bytes_used,
                        hash = chexor(hash, old.name,
                                      old.put_timestamp || '-' ||
                                        old.delete_timestamp || '-' ||
                                        old.object_count || '-' || old.bytes_used);
                END;
    CREATE TRIGGER container_insert AFTER INSERT ON container
                BEGIN
                    UPDATE account_stat
                    SET container_count = container_count + (1 - new.deleted),
                        object_count = object_count + new.object_count,
                        bytes_used = bytes_used + new.bytes_used,
                        hash = chexor(hash, new.name,
                                      new.put_timestamp || '-' ||
                                        new.delete_timestamp || '-' ||
                                        new.object_count || '-' || new.bytes_used);
                END;
    CREATE TRIGGER container_update BEFORE UPDATE ON container
                BEGIN
                    SELECT RAISE(FAIL, 'UPDATE not allowed; DELETE and INSERT');
                END;
      其中ROWID字段表示自增的主键,name字段表示container的名称,put_timestampdelete_timestamp分别表示containerputdelete的时间戳,object_count表示container内的object数, bytes_used  表示已使用的空间,deleted表示container是否标记为删除。
    账号testaccount表中的数据项如下所示:


        表incoming_sync记录到来的同步数据项,其schema如下:
    CREATE TABLE incoming_sync (
                    remote_id TEXT UNIQUE,
                    sync_point INTEGER,
                    updated_at TEXT DEFAULT 0
                );
    CREATE TRIGGER incoming_sync_insert AFTER INSERT ON incoming_sync
                BEGIN
                    UPDATE incoming_sync
                    SET updated_at = STRFTIME('%s''NOW')
                    WHERE ROWID = new.ROWID;
                END;
    CREATE TRIGGER incoming_sync_update AFTER UPDATE ON incoming_sync
                BEGIN
                    UPDATE incoming_sync
                    SET updated_at = STRFTIME('%s''NOW')
                    WHERE ROWID = new.ROWID;
                END;
          remote_id字段表示远程节点的idsync_point字段表示上一次更新所在的行位置,updated_at字段表示更新时间。
    账号test的表incoming_sync中的数据项如下所示:


      表outgoing_sync表示推送出的同步数据项,其schema如下:
    CREATE TABLE outgoing_sync (
                    remote_id TEXT UNIQUE,
                    sync_point INTEGER,
                    updated_at TEXT DEFAULT 0
                );
    CREATE TRIGGER outgoing_sync_insert AFTER INSERT ON outgoing_sync
                BEGIN
                    UPDATE outgoing_sync
                    SET updated_at = STRFTIME('%s''NOW')
                    WHERE ROWID = new.ROWID;
                END;
    CREATE TRIGGER outgoing_sync_update AFTER UPDATE ON outgoing_sync
                BEGIN
                    UPDATE outgoing_sync
                    SET updated_at = STRFTIME('%s''NOW')
                    WHERE ROWID = new.ROWID;
                END;
        remote_id字段表示远程节点的idsync_point字段表示上一次更新所在的行位置,updated_at字段表示更新时间。
    账号test的表remote_id中的数据项如下所示:



    3.Container目录
      Container目录结构和生成过程与Account类似,Containerdb中共有5张表,其中incoming_syncoutgoing_syncschemaAccount中的相同。其他3张表分别为container_statobjectsqlite_sequence
      表container_stat与表account_stat相似,其区别是container_stat存放的是关于container信息:

    CREATE TABLE container_stat (
                    account TEXT,
                    container TEXT,
                    created_at TEXT,
                    put_timestamp TEXT DEFAULT '0',
                    delete_timestamp TEXT DEFAULT '0',
                    object_count INTEGER,
                    bytes_used INTEGER,
                    reported_put_timestamp TEXT DEFAULT '0',
                    reported_delete_timestamp TEXT DEFAULT '0',
                    reported_object_count INTEGER DEFAULT 0,
                    reported_bytes_used INTEGER DEFAULT 0,
                    hash TEXT default '00000000000000000000000000000000',
                    id TEXT,
                    status TEXT DEFAULT '',
                    status_changed_at TEXT DEFAULT '0',
                    metadata TEXT DEFAULT '',
                    x_container_sync_point1 INTEGER DEFAULT -1,
                    x_container_sync_point2 INTEGER DEFAULT -1
                );

      其中account字段表示container所示的accountcontainer字段表示container名称,created_at表示创建时间,put_timestamp表示put request的时间戳,delete_timestamp表示delete request的时间戳,object_count表示object计数,bytes_used表示使用空间,hash表示db文件的哈希值, reported_put_timestamp, reported_delete_timestamp, reported_object_count, reported_bytes_used表示reported的状态信息,id表示统一标识符,status表示container状态,status_changed_at表示更改时间,metadata表示container的元数据,x_container_sync_point1表示同步点1x_container_sync_point2表示同步点2.
          以名称为testcontainer db为例,其中的表container_stat数据项如下:


      表objectschema如下:

    CREATE TABLE object (
                    ROWID INTEGER PRIMARY KEY AUTOINCREMENT,
                    name TEXT,
                    created_at TEXT,
                    size INTEGER,
                    content_type TEXT,
                    etag TEXT,
                    deleted INTEGER DEFAULT 0
                );
    CREATE INDEX ix_object_deleted_name ON object (deleted, name);
    CREATE TRIGGER object_delete AFTER DELETE ON object
                BEGIN
                    UPDATE container_stat
                    SET object_count = object_count - (1 - old.deleted),
                        bytes_used = bytes_used - old.size,
                        hash = chexor(hash, old.name, old.created_at);
                END;
    CREATE TRIGGER object_insert AFTER INSERT ON object
                BEGIN
                    UPDATE container_stat
                    SET object_count = object_count + (1 - new.deleted),
                        bytes_used = bytes_used + new.size,
                        hash = chexor(hash, new.name, new.created_at);
                END;
    CREATE TRIGGER object_update BEFORE UPDATE ON object
                BEGIN
                    SELECT RAISE(FAIL, 'UPDATE not allowed; DELETE and INSERT');
                END;


    test container db的表object数据项如下所示:



    4.tmp目录
        tmp目录作为account/container/object serverpartition目录内写入数据前的临时目录。
    例如,在client向服务端上传某一文件,object server调用DiskFile类的mkstemp方法在创建路径为path/device/tmp的目录。在数据上传完成之后,调用put()方法,将数据移动到相应路径。

    5.async_pending目录
      本地server在与remote server建立http连接或者发送数据时超时导致更新失败时,将把文件放入async_pending目录。这种情况经常发生在系统故障或者是高负荷的情况下。如果更新失败,本次更新被加入队列,然后由Updater继续处理这些失败的更新工作。例如,假设一个container server处于负荷下,此时一个新的对象被加入到系统。当Proxy成功地响应Client的请求时,这个对象将变为直接可访问的。但是container服务器并没有更新对象列表,本次更新将进入队列等待延后的更新。所以,container列表不可能马上就包含这个新对象。随后Updater使用object_sweep扫描device上的async pendings目录,遍历每一个prefix目录并执行升级。一旦完成升级,则移除pending目录下的文件(实际上,是通过调用renamer函数将文件移动到object相应的目录下)。
      为了验证以上过程,通过执行一个并发上传1000个文件的脚本,观察sws50的async_pending目录下的所发生的变化。async_pending的路径为/srv/node/sdc/async_pending/,在执行脚本前,该目录下为空。脚本执行完毕后,async_pending目录下产生了一些prefix目录,cd到一个prefix为cb9的目录中,观察其中的数据:
    root@sws50:/srv/node/sdc/async_pending/cb9# ll
    total 24
    -rw------- 1 swift swift 324 2011-11-08 10:15 69a5ee25ea7a4a4b08ea47102930fcb9-1320718532.01864
    -rw------- 1 swift swift 324 2011-11-08 10:15 69a5ee25ea7a4a4b08ea47102930fcb9-1320718537.04863
    -rw------- 1 swift swift 324 2011-11-08 10:15 69a5ee25ea7a4a4b08ea47102930fcb9-1320718543.08122
    -rw------- 1 swift swift 324 2011-11-08 10:15 69a5ee25ea7a4a4b08ea47102930fcb9-1320718550.13288
    -rw------- 1 swift swift 324 2011-11-08 10:15 69a5ee25ea7a4a4b08ea47102930fcb9-1320718558.18801
    -rw------- 1 swift swift 324 2011-11-08 10:16 69a5ee25ea7a4a4b08ea47102930fcb9-1320718567.25494 
    文件路径的组成如下图所示,其中数据名称是由hash_path后面紧跟-,后面是以发送container requestheader中包含的时间戳所产生:


    Figure6:  async_pendingdirectory represention

    2分钟之后,查看该目录下的文件,仅剩下一个文件:
    root@sws50:/srv/node/sdc/async_pending/cb9# ll
    total 4
    -rw------- 1 swift swift 356 2011-11-08 10:18 69a5ee25ea7a4a4b08ea47102930fcb9-1320718567.25494
    最后,async_pending目录变为空。

      account和containerdb pending文件并不会独立地存在于async_pending目录下,它们的pending文件会与其db文件在一个目录下存放。例如:
      某containerdb文件为b8e7f40f8c2012d17aca4e0483d391d0.db,其pending文件为b8e7f40f8c2012d17aca4e0483d391d0.db.pending,一起存放在suffix目录1d0下。
      再次执行测试脚本观察1d0目录下的变化,执行前pending文件的大小为0kb,执行过程中,pending的大小慢慢增加到12kb左右,接着又缓慢下降直到0kb。读取此过程某一时刻的pending文件。
    其中内容如下所示:
    ':gAIoVQM3MzVxAVUQMTMyMTE4NjczMy4yNTQ0N3ECSgBwAQBVGGFwcGxpY2F0aW9uL29jdGV0LXN0
    \ncmVhbXEDVSBkYmQzZjhmYjQ1ZmQyZjBkZGZmNTA1ODZkNWU0ZGY3ZnEESwB0Lg==\n:gAIoVQM3Mzh
    xAVUQMTMyMTE4NjczMy41MjM4MXECTQDcVRhhcHBsaWNhdGlvbi9vY3RldC1zdHJl\nYW1xA1UgOGI3YzR
    iZGVlYzNkZGU4ZDI5OWU1Yzk1ZmE1N2ExZWVxBEsAdC4=\n:gAIoVQM3MzlxAVUQMTMyMTE4NjczMy42M
    zg0NnECTQCgVRhhcHBsaWNhdGlvbi9vY3RldC1zdHJl\nYW1xA1UgMmQ1ZDlhYjk0MzlkMTNiMmZhODhiZmF
    mNTk3NTRkMjZxBEsAdC4=\n:g..........................................AIoVQM3NDdxAVUQMTM
    yMTE4NjczNC40MzIxNnECSgBoAQBVGGFwcGxpY2F0aW9uL29jdGV0LXN0\ncmVhbXEDVSBjYTgzNmZhY2Fh
    MzY0MGQwNDc4YTU5OGQzZmUzYmRiNHEESwB0Lg==\n:gAIoVQM3NDlxAVUQMTMyMTE4NjczNC42MzA
    1NXECTQCUVRhhcHBsaWNhdGlvbi9vY3RldC1zdHJl\nYW1xA1UgY2Y5NWU3MDIxNWEzOTFlNzcwZDBkODB
    jZjlhN2Q5OTlxBEsAdC4=\n:gAIoVQM3NTBxAVUQMTMyMTE4NjczNC43NTA2MXECSgAoAQBVGGFwcGxpY2
    F0aW9uL29jdGV0LXN0\ncmVhbXEDVSAyYzU4Zjc3ZGIwMGUxMTgxNjZmNjg2Zjc0YzlmZmNjZHEESwB0Lg==\n'

    使用:对以上字符串进行分割成list,我们得到第一个非空元素
    y[1]'gAIoVQM3MzVxAVUQMTMyMTE4NjczMy4yNTQ0N3ECSgBwAQBVGG
    FwcGxpY2F0aW9uL29jdGV0LXN0\ncmVhbXEDVSBkYmQzZjhmYjQ1ZmQyZjBk
    ZGZmNTA1ODZkNWU0ZGY3ZnEESwB0Lg==\n'

    使用pickle模块对其进行解码pickle.loads(y[1].decode('base64')),获得一个dict类型的数据:
    name, timestamp, size, content_type, etag,deleted=
    ('735',
    '1321186733.25447',
    94208,
    'application/octet-stream',
    'dbd3f8fb45fd2f0ddff50586d5e4df7f',
    0)
      表示一个名称为735,大小为94208Bmd5哈希值为dbd3f8fb45fd2f0ddff50586d5e4df7f,可访问的字节流文件。此过程由ContainerBroker类的_commit_puts方法完成,随后使用put_object方法把这些数据项放入container dbobject表中,.pending文件中的数据类型与object表中的字段定义一致。
      从accountcontainerdbobject两者的pending文件处理方式中发现其不同之处在于,dbpending文件在更新完其中的一项数据之后,删除pending文件中的相应的数据项,而object的数据在更新完成之后,移动pending文件到目标目录。

     

    6.quarantined目录

      Auditor进程会在本地服务器上每隔一段时间就扫面一次磁盘来检测account、container、object的完整性。一旦发现不完整的数据,该文件就会被隔离,该目录就称为quarantined目录。为了限制Auditor消耗过多的系统资源,其默认扫描间隔是30秒,每秒最大的扫描文件数为20,最高速率为10Mb/s。

      obj auditor使用AuditorWorker类的object_audit方法来检查文件的完整性,该方法封装了obj server的DiskFile类,该类有一个_handle_close_quarantine方法,用来检测文件是否需要被隔离,如果发现损坏,则直接将文件移动到隔离目录下。随后replicator从其他replica那拷贝新的文件来替换,最后Server计算文件的hash值是否正确。整个处理流程如下所示:



    Figure7: quarantined object处理流程
      为了验证auditor的有效性,做一个简单的测试,在路径为srv/4/node/sdb4/objects/210/82c/003499609ba80372d62aa39a9f9a482c/1321186693.02822.data的文件中随意写入了一串字符。约过了10秒之后,发现sdb4/目录下建立了一个quarantined目录,其中包含object目录,里面损坏了的文件,其路径为/srv/4/node/sdb4/quarantined/objects/003499609ba80372d62aa39a9f9a482c/1321186693.02822.data。此时,打开原目录下的文件,已恢复为修改前的状态。
      account使用AccountAuditor类的account_audit方法,container使用ContainerAuditor类的container_audit方法对目录下的db文件进行检查。然而,我在测试时,对container目录下的某db文件进行了修改,大约经过了数分钟后,该db文件才被隔离。在阅读源代码时,发现accountcontainerauditor的扫面间隔与object差异较大。在类初始化时设置了一个interval的变量,默认为1800s,然后在run_forever中传入该参数到random函数来设置休眠时间,每次执行的间隔在180~1800s之间,也就是330分钟。设置较长间隔的原因,我认为主要是由于每次检查db文件前,需要锁住db文件,如果检查的频率过于频繁会影响存储节点的db正常的读写性能。

    总结
      存储结点上的各路径由不同的进程产生和维护,Accounts目录存放了关于account的信息,主要记录account下的container信息,Containes目录存放了关于 container的信息,主要记录了该container下的object信息,Objects目录则是存放了文件的数据和元数据,tmp目录用于数据写入以上目录前的临时目录, async_pending存放未能及时更新而被加入更新队列的数据,quaraninued路径用于隔离发生损坏的数据
    展开全文
  • swift对象存储

    万次阅读 2016-05-23 12:18:50
    swift对象存储简介OpenStack Object Storage(Swift)是OpenStack开源云计算项目的子项目之一,被称为对象存储,提供了强大的扩展性、冗余和持久性。对象存储,用于永久类型的静态数据的长期存储Swift 最初是由 ...
  • Swift简单存储和读取数据

    千次阅读 2018-06-28 13:58:37
    很多时候App需要存储用户基本信息,可以避免重复调接口获取。这里记录一个非常简单的App存储、读取数据通用方法。class SaveInfo: NSObject { func writeInfo(info: Array&lt;Dictionary&lt;String, Any&...
  • Swift 中的属性分为两类:一种是存储属性,把常量或变量的值作为实例的一部分;另一种是计算属性,它计算一个值,类似于方法的功能,提供了一个处理数据的入口与出口。计算属性可以用于类、结构和枚举里,存储属性...
  • OpenStack Swift 存储策略

    千次阅读 2015-06-28 23:30:51
    OpenStack Swift 对象存储及其存储策略简介 Swift 2.0 于 2014 年 7 月 8 日发布,其中最重要的新特性是存储策略(Storage Policy),该特性改变了以往存储系统中存储策略由设计与实施方决定的做法,让用户能够以...
  • 注意:要在添加区域和辅助存储之前启用SWIFT. 登入管理控制台后找到全局设置在搜索中搜索:swift 然后编辑将false值改成true 然后重启管理服务器的服务 再添加区域的昨天出现:启用SWIFT按钮: 提供SWIFT的账号: ...
  • Swift存储集群进行前期功能调研

    千次阅读 2013-11-22 10:05:55
     Swift是OpenStack开源云计算项目的子项目之一,可以称之为对象存储,它提供了强大的扩展性、冗余性和持久性,可以被用于永久类型的静态数据的长期存储,这些数据可以检索、调整,必要时可以进行更新。最适合存储的...
  • 基于opens tack的swift存储搭建过程

    千次阅读 2017-06-04 11:33:05
    平台服务器安装ubuntu-14.04.4-server-amd64.iso。...使用swift 3.0.0实现。 表1.1:节点ip配置 节点 eth0 硬盘 controller 10.80.118.87   storage1 10.82.25.128 10G sdb
  • Swift3 本地存储array(UserDefaults)

    千次阅读 2017-02-07 15:40:44
    swift3 本地存储array, UserDefaults
  • Swift存储属性

    2018-12-14 13:23:55
    // Swift存储属性 // // Created by Goddog on 15/7/19. // Copyright © 2015年 Goddog. All rights reserved. // import Foundation print("存储属性是指存储在类、结构体里的变量或常量,可分为实例存储...
  • Swift工作原理二

    2016-03-10 10:07:07
    Swift存储系统的工作原理的核心是虚节点(Partition Space)和环(Ring)。 虚节点:用于存放一批数据。存储系统把虚节点看做一个移动的整体。 环:虚节点映射到磁盘的物理地址。 当任何一个模块需要对账号、容器...
  • 对象存储Swift介绍

    千次阅读 2013-09-09 16:38:45
    OpenStack Object Storage(Swift)是OpenStack开源云计算项目的子项目之一,被称为对象存储,提供了强大的扩展性、冗余和持久性。本文将从架构、原理和实践等几方面讲述SwiftSwift并不是文件系统或者实时的数据...
  • swift分布式存储添加节点需要新的节点信息加入到ring中记录下来1、在ring中添加两个节点的信息swift@server1:/etc/swift&gt; export ZONE=4swift@server1:/etc/swift&gt; export STORAGE_LOCAL_...
  • swift存储属性与计算属性的区别
  • Swift对象存储API概述

    千次阅读 2015-08-04 01:05:45
    Swift对象存储API概述 OpenStack对象存储是一个高可用的,分布式的,最终一致的对象/ BLOB存储。您可以使用对象存储接口来创建、修改和获取对象和元数据,这是一组具有代表性的状态转移(REST)网络服务来实现的...
  • 16.部署swift服务|swift配置存储和ring

    千次阅读 2018-07-17 16:01:31
    每个服务都需要做的如下: 配置服务的时候,步骤如下: 创建服务同名的用户(除了keystone),添加到services... 更新数据库(除了swift)   swift是用不到上面的数据库的。   安装swift软件包     M...
  • 对象最终是以二进制文件的方式存储在物理节点上,并且Swift通过创建多个副本等冗余技术达到极高的数据持久性,但是副本的采用是以牺牲更多的存储空间为代价的,那么这里的另外一个问题是能否通过其他的技术来减少...
1 2 3 4 5 ... 20
收藏数 31,054
精华内容 12,421
关键字:

swift存储