非常教程

Ruby 2.4参考手册

PStore

PStore

父类:对象

PStore基于Hash实现基于文件的持久性机制。用户代码可以按名称(键)将Ruby对象的层次结构(值)存储到数据存储文件中。一个对象层次可能只是一个单一的对象。用户代码稍后可以根据需要从数据存储中读取值或甚至更新数据。

事务行为确保任何更改一起成功或失败。这可以用来确保数据存储不会处于暂时状态,其中一些值已更新,而另一些则未更新。

在幕后,Ruby对象通过Marshal存储到数据存储文件中。这具有通常的限制。例如,Proc对象不能编组。

用法示例:

require "pstore"

# a mock wiki object...
class WikiPage
  def initialize( page_name, author, contents )
    @page_name = page_name
    @revisions = Array.new

    add_revision(author, contents)
  end

  attr_reader :page_name

  def add_revision( author, contents )
    @revisions << { :created  => Time.now,
                    :author   => author,
                    :contents => contents }
  end

  def wiki_page_references
    [@page_name] + @revisions.last[:contents].scan(/\b(?:[A-Z]+[a-z]+){2,}/)
  end

  # ...
end

# create a new page...
home_page = WikiPage.new( "HomePage", "James Edward Gray II",
                          "A page about the JoysOfDocumentation..." )

# then we want to update page data and the index together, or not at all...
wiki = PStore.new("wiki_pages.pstore")
wiki.transaction do  # begin transaction; do all of this or none of it
  # store page...
  wiki[home_page.page_name] = home_page
  # ensure that an index has been created...
  wiki[:wiki_index] ||= Array.new
  # update wiki index...
  wiki[:wiki_index].push(*home_page.wiki_page_references)
end                   # commit changes to wiki data store file

### Some time later... ###

# read wiki data...
wiki.transaction(true) do  # begin read-only transaction, no changes allowed
  wiki.roots.each do |data_root_name|
    p data_root_name
    p wiki[data_root_name]
  end
end

交易模式

默认情况下,只有操作系统(和底层硬件)不会引发任何意外的I / O错误,才能确保文件完整性。如果在PStore写入文件时发生I / O错误,则文件将被损坏。

你可以通过设置pstore.ultra_safe = true来防止这种情况。但是,这会导致性能下降,只能在支持原子文件重命名的平台上运行。ultra_safe有关详细信息,请参阅文档。

不用说,如果您使用PStore存储有价值的数据,那么您应该不时备份PStore文件。

常量

CHECKSUM_ALGO

用于解除Ruby垃圾收集器的常量。

EMPTY_MARSHAL_CHECKSUM EMPTY_MARSHAL_DATA EMPTY_STRING RDWR_ACCESS RD_ACCESS WR_ACCESS

属性

ultra_safeRW

即使在出现不太可能发生的错误情况(如空间不足条件和其他异常的操作系统文件系统错误)时,PStore是否应尽全力防止文件损坏。设置这个标志的价格是以性能损失的形式出现的。

此标志只对文件重命名为原子的平台有效(例如所有POSIX平台:Linux,MacOS X,FreeBSD等)。默认值是false。

公共类方法

new(file, thread_safe = false) Show source

要构建PStore对象,请传入您希望存储数据的文件路径。

PStore对象总是可重入的。但是,如果将thread_safe设置为true,那么它将成为线程安全的代价是性能较低

# File lib/pstore.rb, line 118
def initialize(file, thread_safe = false)
  dir = File::dirname(file)
  unless File::directory? dir
    raise PStore::Error, format("directory %s does not exist", dir)
  end
  if File::exist? file and not File::readable? file
    raise PStore::Error, format("file %s not readable", file)
  end
  @filename = file
  @abort = false
  @ultra_safe = false
  @thread_safe = thread_safe
  @lock = Thread::Mutex.new
end

公共实例方法

Show source

名称从PStore文件数据中检索一个值。将以该根名称存储的Ruby对象的层次结构将被返回。

警告:此方法仅在#transaction中有效。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 154
def [](name)
  in_transaction
  @table[name]
end

[]=(name, value) Show source

将单个Ruby对象或Ruby对象的层次结构存储在数据存储文件的根名下。为数据存储中已有的名称指定clobbers旧数据。

例:

require "pstore"

store = PStore.new("data_file.pstore")
store.transaction do  # begin transaction
  # load some data into the store...
  store[:single_object] = "My data..."
  store[:obj_hierarchy] = { "Kev Jackson" => ["rational.rb", "pstore.rb"],
                            "James Gray"  => ["erb.rb", "pstore.rb"] }
end                   # commit changes to data store file

警告:此方法仅在#transaction中有效,且不能为只读。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 199
def []=(name, value)
  in_transaction_wr
  @table[name] = value
end

abort() Show source

结束当前的#事务,放弃对数据存储的任何更改。

例:

require "pstore"

store = PStore.new("data_file.pstore")
store.transaction do  # begin transaction
  store[:one] = 1     # this change is not applied, see below...
  store[:two] = 2     # this change is not applied, see below...

  store.abort         # end transaction here, discard all changes

  store[:three] = 3   # this change is never reached
end

警告:此方法仅在#transaction中有效。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 287
def abort
  in_transaction
  @abort = true
  throw :pstore_abort_transaction
end

commit() Show source

结束当前的#事务,立即向数据存储提交任何更改。

例:

require "pstore"

store = PStore.new("data_file.pstore")
store.transaction do  # begin transaction
  # load some data into the store...
  store[:one] = 1
  store[:two] = 2

  store.commit        # end transaction here, committing changes

  store[:three] = 3   # this change is never reached
end

警告:此方法仅在#transaction中有效。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 261
def commit
  in_transaction
  @abort = false
  throw :pstore_abort_transaction
end

delete(name) Show source

名称中删除数据存储中的对象层次结构。

警告:此方法仅在#transaction中有效,且不能为只读。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 209
def delete(name)
  in_transaction_wr
  @table.delete name
end

fetch(name, default=PStore::Error) Show source

这个方法就像#[]一样,除此之外你也可以为对象提供一个默认值。如果在数据存储中未找到指定的名称,则将返回默认值。如果不指定默认值,则在未找到对象时会引发PStore :: Error。

警告:此方法仅在#transaction中有效。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 168
def fetch(name, default=PStore::Error)
  in_transaction
  unless @table.key? name
    if default == PStore::Error
      raise PStore::Error, format("undefined root name `%s'", name)
    else
      return default
    end
  end
  @table[name]
end

path() Show source

返回数据存储文件的路径。

# File lib/pstore.rb, line 235
def path
  @filename
end

root?(name) Show source

如果提供的名称当前位于数据存储中,则返回true 。

警告:此方法仅在#transaction中有效。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 230
def root?(name)
  in_transaction
  @table.key? name
end

roots() Show source

返回存储中当前所有对象层次结构的名称。

警告:此方法仅在#transaction中有效。如果在任何其他时间调用它将引发PStore :: Error。

# File lib/pstore.rb, line 220
def roots
  in_transaction
  @table.keys
end

transaction(read_only = false) { |pstore| ... } Show source

打开数据存储的新事务。在传递给此方法的块内部执行的代码可以从数据存储文件读取数据并将其写入数据存储文件。

在块的末尾,更改将自动提交到数据存储。您可以通过调用#commit或#abort提前退出事务。有关如何处理更改的详细信息,请参阅这些方法。在块中提高未捕获的异常等同于调用#abort。

如果read_only设置为true,则只能在事务处理期间从数据存储区读取数据,并且任何尝试更改数据的操作都将引发PStore :: Error。

请注意,PStore不支持嵌套事务。

# File lib/pstore.rb, line 310
def transaction(read_only = false)  # :yields:  pstore
  value = nil
  if !@thread_safe
    raise PStore::Error, "nested transaction" unless @lock.try_lock
  else
    begin
      @lock.lock
    rescue ThreadError
      raise PStore::Error, "nested transaction"
    end
  end
  begin
    @rdonly = read_only
    @abort = false
    file = open_and_lock_file(@filename, read_only)
    if file
      begin
        @table, checksum, original_data_size = load_data(file, read_only)

        catch(:pstore_abort_transaction) do
          value = yield(self)
        end

        if !@abort && !read_only
          save_data(checksum, original_data_size, file)
        end
      ensure
        file.close
      end
    else
      # This can only occur if read_only == true.
      @table = {}
      catch(:pstore_abort_transaction) do
        value = yield(self)
      end
    end
  ensure
    @lock.unlock
  end
  value
end

私有实例方法

empty_marshal_checksum() Show source

# File lib/pstore.rb, line 487
def empty_marshal_checksum
  EMPTY_MARSHAL_CHECKSUM
end

empty_marshal_data() Show source

# File lib/pstore.rb, line 484
def empty_marshal_data
  EMPTY_MARSHAL_DATA
end

in_transaction() Show source

如果调用代码不在#transaction中,则引发PStore :: Error。

# File lib/pstore.rb, line 134
def in_transaction
  raise PStore::Error, "not in transaction" unless @lock.locked?
end

in_transaction_wr() Show source

如果调用代码不在#transaction中,或者代码是只读的#transaction,则引发PStore :: Error。

# File lib/pstore.rb, line 141
def in_transaction_wr
  in_transaction
  raise PStore::Error, "in read-only transaction" if @rdonly
end

load_data(file, read_only) Show source

加载给定的PStore文件。如果read_only为true,则将返回未编组哈希。如果read_only为false,则将返回一个三元组:数组的哈希值,数据的校验和以及数据的大小。

# File lib/pstore.rb, line 398
def load_data(file, read_only)
  if read_only
    begin
      table = load(file)
      raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
    rescue EOFError
      # This seems to be a newly-created file.
      table = {}
    end
    table
  else
    data = file.read
    if data.empty?
      # This seems to be a newly-created file.
      table = {}
      checksum = empty_marshal_checksum
      size = empty_marshal_data.bytesize
    else
      table = load(data)
      checksum = CHECKSUM_ALGO.digest(data)
      size = data.bytesize
      raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
    end
    data.replace(EMPTY_STRING)
    [table, checksum, size]
  end
end

on_windows?() Show source

# File lib/pstore.rb, line 426
def on_windows?
  is_windows = RUBY_PLATFORM =~ /mswin|mingw|bccwin|wince/
  self.class.__send__(:define_method, :on_windows?) do
    is_windows
  end
  is_windows
end

open_and_lock_file(filename, read_only) Show source

打开指定的文件名(以只读模式或读写模式)并将其锁定以便读取或写入。

打开的File对象将被返回。如果read_only为true,并且文件不存在,则返回nil。

所有异常都会传播。

# File lib/pstore.rb, line 373
def open_and_lock_file(filename, read_only)
  if read_only
    begin
      file = File.new(filename, RD_ACCESS)
      begin
        file.flock(File::LOCK_SH)
        return file
      rescue
        file.close
        raise
      end
    rescue Errno::ENOENT
      return nil
    end
  else
    file = File.new(filename, RDWR_ACCESS)
    file.flock(File::LOCK_EX)
    return file
  end
end

save_data(original_checksum, original_file_size, file) Show source

# File lib/pstore.rb, line 434
def save_data(original_checksum, original_file_size, file)
  new_data = dump(@table)

  if new_data.bytesize != original_file_size || CHECKSUM_ALGO.digest(new_data) != original_checksum
    if @ultra_safe && !on_windows?
      # Windows doesn't support atomic file renames.
      save_data_with_atomic_file_rename_strategy(new_data, file)
    else
      save_data_with_fast_strategy(new_data, file)
    end
  end

  new_data.replace(EMPTY_STRING)
end

save_data_with_atomic_file_rename_strategy(data, file) Show source

# File lib/pstore.rb, line 449
def save_data_with_atomic_file_rename_strategy(data, file)
  temp_filename = "#{@filename}.tmp.#{Process.pid}.#{rand 1000000}"
  temp_file = File.new(temp_filename, WR_ACCESS)
  begin
    temp_file.flock(File::LOCK_EX)
    temp_file.write(data)
    temp_file.flush
    File.rename(temp_filename, @filename)
  rescue
    File.unlink(temp_file) rescue nil
    raise
  ensure
    temp_file.close
  end
end

save_data_with_fast_strategy(data, file) Show source

# File lib/pstore.rb, line 465
def save_data_with_fast_strategy(data, file)
  file.rewind
  file.write(data)
  file.truncate(data.bytesize)
end
PStore
PStore::Error 详细
Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct