whispr 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -1
- data/lib/whispr.rb +73 -34
- data/lib/whispr/version.rb +1 -1
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -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 #
|
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
|
data/lib/whispr.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
100
|
-
|
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
|
-
|
112
|
-
|
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
|
-
|
125
|
-
|
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
|
-
|
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
|
data/lib/whispr/version.rb
CHANGED
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
|
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-
|
12
|
+
date: 2014-01-31 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ''
|
15
15
|
email: whispr@simulacre.org
|