simple_stats_store 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 03dc5993bc4a5e7ec010d5601add13295a9d3cfc
4
+ data.tar.gz: cfe61488fb2db2b0a2562515ee6efc2fcde61501
5
+ SHA512:
6
+ metadata.gz: 4bb37b8ff0d17d9d5bac6258bc6af92a840ba68dda73e3f50d45a247a10d37e5b27e13d885910e3fe51379c3b51a00975113cdf07401ae8776ae90ba0063f382
7
+ data.tar.gz: fd35eec5a1d2904de47e6da818ab395b16b887b605506d05e4d27a10d48a7e9cb4868a007dbca4bc9c1427300446363b3a77308472c2cdae4c1d64354b9b1a32
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Simple Stats Store
2
+
3
+ ## Introduction
4
+
5
+ The purpose of Simple Stats Store is to provide a simple and lightweight method
6
+ for multiple processes to dump data into an SQLite database without contention.
7
+
8
+ It is appropriate to be used when:
9
+
10
+ * There are multiple threads or processes submitting statistics
11
+ * Data concurrency is less important than avoiding waiting on database locks
12
+
13
+ This is achieved by the threads dropping uniquely named files into a common
14
+ directory containing the statistics which are then picked up by a single thread
15
+ that is the sole accessor of the database.
16
+
17
+ ## Usage
18
+
19
+ ### General
20
+
21
+ Create the repository for temporary data files:
22
+
23
+ ```ruby
24
+ require 'simple_stats_store/file_dump'
25
+
26
+ dir = '/path/to/temporary/data/directory'
27
+ Dir.mkdir(dir)
28
+ data_dump = SimpleStatsStore::FileDump.new(dir)
29
+ ```
30
+
31
+ ### Server
32
+
33
+ Set up the database:
34
+
35
+ ```ruby
36
+ require 'simple_stats_store/server'
37
+
38
+ db_file = '/path/to/database.sql'
39
+ ActiveRecord::Base.establish_connection(
40
+ adapter: :sqlite3,
41
+ database: db_file
42
+ )
43
+ ActiveRecord::Schema.define do
44
+ create_table :table do |table|
45
+ table.column :timestamp, :string
46
+ table.column :key_1, :integer
47
+ table.column :key_2, :float
48
+ # etc.
49
+ end
50
+ end
51
+ class Table < ActiveRecord::Base
52
+ end
53
+
54
+ ssss = SimpleStatsStore::Server.new(
55
+ data_dump: data_dump,
56
+ models: { table_ref: Table }
57
+ )
58
+
59
+ t_next = Time.new + 300
60
+ server_pid = ssss.run do
61
+ if Time.new >= t_next
62
+ # Code to be executed every 5 minutes
63
+ # ...
64
+ t_next += 300
65
+ end
66
+ end
67
+ ```
68
+
69
+ ### Client
70
+
71
+ Write data
72
+
73
+ ```ruby
74
+ data_dump.write(
75
+ table_ref,
76
+ {
77
+ timestamp: Time.new.to_s,
78
+ key_1: value_1,
79
+ key_2: value_2,
80
+ # etc.
81
+ }
82
+ )
83
+ ```
84
+
85
+ ## License
86
+
87
+ Simple Stats Store is available to everyone under the terms of the MIT open source licence. Take a look at the LICENSE file in the code.
88
+
89
+ Copyright (c) 2015 BBC
@@ -0,0 +1,5 @@
1
+ require 'simple_stats_store/server'
2
+ require 'simple_stats_store/file_dump'
3
+
4
+ module SimpleStatsStore
5
+ end
@@ -0,0 +1,40 @@
1
+ require 'tempfile'
2
+
3
+ module SimpleStatsStore
4
+ class FileDump
5
+ def initialize(dir)
6
+ @dir = dir
7
+ end
8
+
9
+ def files_contents
10
+ contents = []
11
+ Dir["#{@dir}/*"].each do |f|
12
+ data = File.open(f, 'r').read
13
+ if /\n---\n$/.match(data)
14
+ contents << data
15
+ File.delete(f)
16
+ end
17
+ end
18
+ contents
19
+ end
20
+
21
+ def each(&block)
22
+ files_contents.each &block
23
+ end
24
+
25
+ def write(model, data)
26
+ i = 0
27
+ while File.exists?(File.expand_path("sss-#{$$}-#{Time.new.to_i}-#{i}.stats", @dir))
28
+ i += 1
29
+ end
30
+ File.open(File.expand_path("sss-#{$$}-#{Time.new.to_i}-#{i}.stats", @dir), 'w') do |f|
31
+ f.puts "---"
32
+ f.puts model
33
+ data.each do |key, value|
34
+ f.puts "#{key.to_s}: #{value}"
35
+ end
36
+ f.puts "---"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ module SimpleStatsStore
2
+ class NilDump
3
+ def each(&block)
4
+ [].each(&block)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ module SimpleStatsStore
2
+ class Server
3
+ def initialize(options)
4
+ @data_dump = options[:data_dump]
5
+ @models = options[:models]
6
+ end
7
+
8
+ def scan
9
+ @data_dump.each do |stats|
10
+ lines = stats.split("\n")
11
+ if lines.shift != '---' or lines.pop != '---'
12
+ puts "Corrupt statistics"
13
+ return false
14
+ end
15
+
16
+ model = lines.shift.strip
17
+ data = {}
18
+ lines.each do |l|
19
+ k, v = l.split(/:/, 2)
20
+ data[k.strip.to_sym] = v.strip
21
+ end
22
+
23
+ @models[model.to_sym].create(data)
24
+ end
25
+ end
26
+
27
+ def run(&block)
28
+ Process.fork do
29
+ loop do
30
+ self.scan
31
+ yield if block_given?
32
+ sleep 0.1
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_stats_store
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Joe Haig
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-15 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Using SQLite3 to store statistics from a multithreaded application
14
+ email: joe.haig@bbc.co.uk
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - lib/simple_stats_store.rb
21
+ - lib/simple_stats_store/file_dump.rb
22
+ - lib/simple_stats_store/nil_dump.rb
23
+ - lib/simple_stats_store/server.rb
24
+ homepage: https://github.com/bbc/simple_stats_store
25
+ licenses:
26
+ - MIT
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 2.2.2
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Simple Stats Store
48
+ test_files: []