whispr 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|