whispr 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,10 @@
1
+ 0.1.0
2
+ - [2](https://github.com/simulacre/whispr/pull/2): allows closing the filehandle [ovesh](https://github.com/ovesh)
3
+ - IOError caught when reading header will be tagged as Whispr::Error rather than raising Whispr::CorruptWhisprFile
4
+ - support testing Whispr from specs using StringIO objects
5
+
1
6
  0.0.3
2
- - fixes: branch test and call to #update_one from #udpate_many
7
+ - fixes: branch test and call to #update_one from #update
3
8
  - [1](https://github.com/simulacre/whispr/pull/1): allows passing array to #update [ovesh](https://github.com/ovesh)
4
9
 
5
10
  0.0.2
@@ -75,57 +75,86 @@ class Whispr
75
75
  [precision, points]
76
76
  end
77
77
 
78
- # Create whipser file.
78
+ # Create whipser file on the file system and prepopulate it.
79
79
  # @param [String] path
80
80
  # @param [Array] archiveList each archive is an array with two elements: [secondsPerPoint,numberOfPoints]
81
81
  # @param [Hash] opts
82
- # @option opts [Float] :xff the fraction of data points in a propagation interval that must have known values for a propagation to occur
83
- # @option opts [Symbol] :aggregationMethod the function to use when propogating data; must be one of AGGR_TYPES[1..-1]
82
+ # @option opts [Float] :xff (0.5) the fraction of data points in a propagation interval that must have known values for a propagation to occur
83
+ # @option opts [Symbol] :aggregationMethod (average) the function to use when propogating data; must be one of AGGR_TYPES[1..-1]
84
84
  # @option opts [Boolean] :overwrite (false)
85
+ # @option opts [Boolean] :sparse (false)
85
86
  # @raise [InvalidConfiguration] if the archiveList is inavlid, or if 'path' exists and :overwrite is not true
86
87
  # @see Whsipr.validateArchiveList
87
88
  def create(path, archiveList, opts = {})
88
- opts = {:xff => 0.5, :aggregationMethod => :average, :sparse => false, :overwrite => false}.merge(opts)
89
- unless AGGR_TYPES[1..-1].include?(opts[:aggregationMethod])
90
- raise InvalidConfiguration.new("aggregationMethod must be one of #{AGGR_TYPES[1..-1]}")
91
- end
92
-
89
+ validate_opts(opts)
93
90
  validateArchiveList!(archiveList)
94
91
  raise InvalidConfiguration.new("File #{path} already exists!") if File.exists?(path) && !opts[:overwrite]
95
92
 
96
93
  # if file exists it will be truncated
97
94
  File.open(path, "wb") do |fh|
98
95
  fh.flock(File::LOCK_EX)
99
- aggregationType = AGGR_TYPES.index(opts[:aggregationMethod])
100
- oldest = archiveList.map{|spp, points| spp * points }.sort.last
101
- packedMetadata = [aggregationType, oldest, opts[:xff], archiveList.length].pack(METADATA_FMT)
102
- fh.write(packedMetadata)
103
- headerSize = METADATA_SIZE + (ARCHIVE_INFO_SIZE * archiveList.length)
104
- archiveOffsetPointer = headerSize
105
- archiveList.each do |spp, points|
106
- archiveInfo = [archiveOffsetPointer, spp, points].pack(ARCHIVE_INFO_FMT)
107
- fh.write(archiveInfo)
108
- archiveOffsetPointer += (points * POINT_SIZE)
109
- end
96
+ prepopulate(fh, archiveList, opts)
97
+ end
110
98
 
111
- if opts[:sparse]
112
- fh.seek(archiveOffsetPointer - headerSize - 1)
113
- fh.write("\0")
114
- else
115
- remaining = archiveOffsetPointer - headerSize
116
- zeroes = "\x00" * CHUNK_SIZE
117
- while remaining > CHUNK_SIZE
118
- fh.write(zeroes)
119
- remaining -= CHUNK_SIZE
120
- end
121
- fh.write(zeroes[0..remaining])
122
- end
99
+ new(path)
100
+ end
123
101
 
124
- fh.flush
125
- fh.fsync rescue nil
102
+ # Set defaults for the options to #create and #prepopulate as well as validate the supplied options.
103
+ # @param [Hash] opts
104
+ # @return [Hash] updated options
105
+ def validate_opts(opts = {})
106
+ opts = {:xff => 0.5, :aggregationMethod => :average, :sparse => false, :overwrite => false}.merge(opts)
107
+ unless AGGR_TYPES[1..-1].include?(opts[:aggregationMethod])
108
+ raise InvalidConfiguration.new("aggregationMethod must be one of #{AGGR_TYPES[1..-1]}")
126
109
  end
110
+ opts
111
+ end
127
112
 
128
- new(path)
113
+ # Build the header and reserve space for the archives in the Whispr file.
114
+ #
115
+ # You probably don't want to use this method, you probably want to use
116
+ # #create instead. Calls to prepopulate MUST be preceeded by a call to
117
+ # validateArchiveList! with the archiveList argument.
118
+ #
119
+ # @param [File] the filehandle that will hold the archive
120
+ # @param [Array] archiveList each archive is an array with two elements: [secondsPerPoint,numberOfPoints]
121
+ # @param [Hash] opts
122
+ # @option opts [Float] :xff the fraction of data points in a propagation interval that must have known values for a propagation to occur
123
+ # @option opts [Symbol] :aggregationMethod the function to use when propogating data; must be one of AGGR_TYPES[1..-1]
124
+ # @option opts [Boolean] :overwrite (false)
125
+ # @raise [InvalidConfiguration] if the archiveList is inavlid, or if 'path' exists and :overwrite is not true
126
+ # @see Whsipr.validateArchiveList
127
+ # @see Whsipr.create
128
+ def prepopulate(fh, archiveList, opts = {})
129
+ opts = validate_opts(opts)
130
+ aggregationType = AGGR_TYPES.index(opts[:aggregationMethod])
131
+ oldest = archiveList.map{|spp, points| spp * points }.sort.last
132
+ packedMetadata = [aggregationType, oldest, opts[:xff], archiveList.length].pack(METADATA_FMT)
133
+ fh.write(packedMetadata)
134
+ headerSize = METADATA_SIZE + (ARCHIVE_INFO_SIZE * archiveList.length)
135
+ archiveOffsetPointer = headerSize
136
+ archiveList.each do |spp, points|
137
+ archiveInfo = [archiveOffsetPointer, spp, points].pack(ARCHIVE_INFO_FMT)
138
+ fh.write(archiveInfo)
139
+ archiveOffsetPointer += (points * POINT_SIZE)
140
+ end
141
+
142
+ if opts[:sparse]
143
+ fh.seek(archiveOffsetPointer - headerSize - 1)
144
+ fh.write("\0")
145
+ else
146
+ remaining = archiveOffsetPointer - headerSize
147
+ zeroes = "\x00" * CHUNK_SIZE
148
+ while remaining > CHUNK_SIZE
149
+ fh.write(zeroes)
150
+ remaining -= CHUNK_SIZE
151
+ end
152
+ fh.write(zeroes[0..remaining])
153
+ end
154
+
155
+ fh.flush
156
+ fh.fsync rescue nil
157
+ fh
129
158
  end
130
159
 
131
160
  # Is the provided archive list valid?
@@ -253,6 +282,14 @@ class Whispr
253
282
  end
254
283
  end
255
284
 
285
+ def closed?
286
+ @fh.closed?
287
+ end
288
+
289
+ def close
290
+ @fh.close
291
+ end
292
+
256
293
  private
257
294
 
258
295
 
@@ -273,6 +310,8 @@ private
273
310
  :offset => offset
274
311
  }
275
312
  end
313
+ rescue IOError => e
314
+ raise e.extend(Error)
276
315
  rescue => e
277
316
  raise CorruptWhisprFile.exception(e)
278
317
  ensure
@@ -1,3 +1,3 @@
1
1
  class Whispr
2
- VERSION = '0.0.3'
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whispr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-09 00:00:00.000000000 Z
12
+ date: 2014-01-31 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ''
15
15
  email: whispr@simulacre.org