ricardochimal-taps 0.2.9 → 0.2.12

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -27,7 +27,6 @@ or when you want to push a local database to a taps server
27
27
  * Blob data may not transfer properly, I suspect that SQLite3 is modifying some native ruby objects.
28
28
  * Foreign Keys get lost in the schema transfer
29
29
  * Large tables (>1 million rows with a large number of columns) get slower as the offset gets larger. This is due to it being inefficient having large offset values in queries.
30
- * Character encoding problems should be more transparent but they're not, it usually involves looking at the server log to see the error.
31
30
 
32
31
  == Meta
33
32
 
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ begin
12
12
  s.add_dependency 'activerecord', '= 2.2.2'
13
13
  s.add_dependency 'thor', '= 0.9.9'
14
14
  s.add_dependency 'rest-client', '~> 0.9.0'
15
- s.add_dependency 'sequel', '~> 2.10.0'
15
+ s.add_dependency 'sequel', '~> 2.11.0'
16
16
  s.add_dependency 'sqlite3-ruby', '~> 1.2.0'
17
17
 
18
18
  s.rubyforge_project = "taps"
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 9
2
+ :patch: 12
3
3
  :major: 0
4
4
  :minor: 2
data/bin/taps CHANGED
@@ -5,7 +5,7 @@ gem 'activerecord', '= 2.2.2'
5
5
  gem 'thor', '= 0.9.9'
6
6
  gem 'rest-client', '~> 0.9.0'
7
7
  gem 'sinatra', '~> 0.9.0'
8
- gem 'sequel', '~> 2.10.0'
8
+ gem 'sequel', '~> 2.11.0'
9
9
  gem 'sqlite3-ruby', '~> 1.2.0'
10
10
 
11
11
  require File.dirname(__FILE__) + '/../lib/taps/cli'
data/lib/taps/cli.rb CHANGED
@@ -36,6 +36,11 @@ class Cli < Thor
36
36
  clientxfer(:cmd_send, database_url, remote_url)
37
37
  end
38
38
 
39
+ desc "version", "Taps version"
40
+ def version
41
+ puts Taps.version
42
+ end
43
+
39
44
  def clientxfer(method, database_url, remote_url)
40
45
  if options[:chunksize]
41
46
  Taps::Config.chunksize = options[:chunksize] < 100 ? 100 : options[:chunksize]
@@ -70,11 +70,21 @@ class ClientSession
70
70
  end
71
71
 
72
72
  def cmd_send
73
- verify_server
74
- cmd_send_schema
75
- cmd_send_data
76
- cmd_send_indexes
77
- cmd_send_reset_sequences
73
+ begin
74
+ verify_server
75
+ cmd_send_schema
76
+ cmd_send_data
77
+ cmd_send_indexes
78
+ cmd_send_reset_sequences
79
+ rescue RestClient::Exception => e
80
+ if e.respond_to?(:response)
81
+ puts "!!! Caught Server Exception"
82
+ puts "#{e.response.body}"
83
+ exit(1)
84
+ else
85
+ raise
86
+ end
87
+ end
78
88
  end
79
89
 
80
90
  def cmd_send_indexes
@@ -108,20 +118,22 @@ class ClientSession
108
118
  db.tables.each do |table_name|
109
119
  table = db[table_name]
110
120
  count = table.count
111
- columns = table.columns
112
- order = columns.include?(:id) ? :id : columns.first
121
+ primary_key = db.primary_key(table_name.to_sym)
122
+ order = primary_key ? [primary_key.to_sym] : table.columns
113
123
  chunksize = self.default_chunksize
114
124
 
115
125
  progress = ProgressBar.new(table_name.to_s, count)
116
126
 
117
127
  offset = 0
118
128
  loop do
119
- rows = Taps::Utils.format_data(table.order(order).limit(chunksize, offset).all)
120
- break if rows == { }
129
+ row_size = 0
130
+ chunksize = Taps::Utils.calculate_chunksize(chunksize) do |c|
131
+ rows = Taps::Utils.format_data(table.order(*order).limit(c, offset).all)
132
+ break if rows == { }
121
133
 
122
- gzip_data = Taps::Utils.gzip(Marshal.dump(rows))
134
+ row_size = rows[:data].size
135
+ gzip_data = Taps::Utils.gzip(Marshal.dump(rows))
123
136
 
124
- chunksize = Taps::Utils.calculate_chunksize(chunksize) do
125
137
  begin
126
138
  session_resource["tables/#{table_name}"].post(gzip_data, http_headers({
127
139
  :content_type => 'application/octet-stream',
@@ -135,8 +147,10 @@ class ClientSession
135
147
  end
136
148
  end
137
149
 
138
- progress.inc(rows[:data].size)
139
- offset += rows[:data].size
150
+ progress.inc(row_size)
151
+ offset += row_size
152
+
153
+ break if row_size == 0
140
154
  end
141
155
 
142
156
  progress.finish
@@ -156,11 +170,21 @@ class ClientSession
156
170
  end
157
171
 
158
172
  def cmd_receive
159
- verify_server
160
- cmd_receive_schema
161
- cmd_receive_data
162
- cmd_receive_indexes
163
- cmd_reset_sequences
173
+ begin
174
+ verify_server
175
+ cmd_receive_schema
176
+ cmd_receive_data
177
+ cmd_receive_indexes
178
+ cmd_reset_sequences
179
+ rescue RestClient::Exception => e
180
+ if e.respond_to?(:response)
181
+ puts "!!! Caught Server Exception"
182
+ puts "#{e.response.body}"
183
+ exit(1)
184
+ else
185
+ raise
186
+ end
187
+ end
164
188
  end
165
189
 
166
190
  def cmd_receive_data
@@ -199,8 +223,8 @@ class ClientSession
199
223
 
200
224
  def fetch_table_rows(table_name, chunksize, offset)
201
225
  response = nil
202
- chunksize = Taps::Utils.calculate_chunksize(chunksize) do
203
- response = session_resource["tables/#{table_name}/#{chunksize}?offset=#{offset}"].get(http_headers)
226
+ chunksize = Taps::Utils.calculate_chunksize(chunksize) do |c|
227
+ response = session_resource["tables/#{table_name}/#{c}?offset=#{offset}"].get(http_headers)
204
228
  end
205
229
  raise CorruptedData unless Taps::Utils.valid_data?(response.to_s, response.headers[:taps_checksum])
206
230
 
@@ -1,3 +1,5 @@
1
+ require 'thread'
2
+
1
3
  Sequel::Model.db = Sequel.connect(Taps::Config.taps_database_url)
2
4
 
3
5
  class DbSession < Sequel::Model
@@ -9,17 +11,51 @@ class DbSession < Sequel::Model
9
11
  timestamp :last_access
10
12
  end
11
13
 
14
+ @@connections = {}
15
+ @@mutex = Mutex.new
16
+
12
17
  def connection
13
- @@connections ||= {}
14
- @@connections[key] ||= Sequel.connect(database_url)
18
+ @@mutex.synchronize {
19
+ conn =
20
+ if @@connections.key?(key)
21
+ @@connections[key].first
22
+ else
23
+ Sequel.connect(database_url)
24
+ end
25
+ @@connections[key] = [conn, Time.now]
26
+ return conn
27
+ }
15
28
  end
16
29
 
17
30
  def disconnect
18
- if defined? @@connections and @@connections[key]
19
- @@connections[key].disconnect
20
- @@connections.delete key
21
- end
31
+ @@mutex.synchronize {
32
+ if @@connections.key?(key)
33
+ conn, time = @@connections.delete(key)
34
+ conn.disconnect
35
+ end
36
+ }
22
37
  end
38
+
39
+ # Removes connections that have not been accessed within the
40
+ # past thirty seconds.
41
+ def self.cleanup
42
+ @@mutex.synchronize {
43
+ now = Time.now
44
+ @@connections.each do |key, (conn, time)|
45
+ if now - time > 30
46
+ @@connections.delete(key)
47
+ conn.disconnect
48
+ end
49
+ end
50
+ }
51
+ end
52
+
53
+ Thread.new {
54
+ while true
55
+ sleep 30
56
+ cleanup
57
+ end
58
+ }.run
23
59
  end
24
60
 
25
61
  DbSession.create_table! unless DbSession.table_exists?
data/lib/taps/server.rb CHANGED
@@ -10,7 +10,8 @@ class Server < Sinatra::Default
10
10
  end
11
11
 
12
12
  error do
13
- "Application error"
13
+ e = request.env['sinatra.error']
14
+ "Taps Server Error: #{e}"
14
15
  end
15
16
 
16
17
  before do
@@ -116,9 +117,9 @@ class Server < Sinatra::Default
116
117
 
117
118
  db = session.connection
118
119
  table = db[params[:table].to_sym]
119
- columns = table.columns
120
- order = columns.include?(:id) ? :id : columns.first
121
- raw_data = Marshal.dump(Taps::Utils.format_data(table.order(order).limit(chunk, offset).all))
120
+ primary_key = db.primary_key(params[:table].to_sym)
121
+ order = primary_key ? [primary_key.to_sym] : table.columns
122
+ raw_data = Marshal.dump(Taps::Utils.format_data(table.order(*order).limit(chunk, offset).all))
122
123
  gzip_data = Taps::Utils.gzip(raw_data)
123
124
  response['Taps-Checksum'] = Taps::Utils.checksum(gzip_data).to_s
124
125
  response['Content-Type'] = "application/octet-stream"
data/lib/taps/utils.rb CHANGED
@@ -41,19 +41,32 @@ module Utils
41
41
  end
42
42
 
43
43
  def calculate_chunksize(old_chunksize)
44
- t1 = Time.now
45
- yield
44
+ chunksize = old_chunksize
45
+
46
+ retries = 0
47
+ begin
48
+ t1 = Time.now
49
+ yield chunksize
50
+ rescue Errno::EPIPE
51
+ retries += 1
52
+ raise if retries > 1
53
+ # we got disconnected, the chunksize could be too large
54
+ # so we're resetting to a very small value
55
+ chunksize = 100
56
+ retry
57
+ end
58
+
46
59
  t2 = Time.now
47
60
 
48
61
  diff = t2 - t1
49
62
  new_chunksize = if diff > 3.0
50
- (old_chunksize / 3).ceil
63
+ (chunksize / 3).ceil
51
64
  elsif diff > 1.1
52
- old_chunksize - 100
65
+ chunksize - 100
53
66
  elsif diff < 0.8
54
- old_chunksize * 2
67
+ chunksize * 2
55
68
  else
56
- old_chunksize + 100
69
+ chunksize + 100
57
70
  end
58
71
  new_chunksize = 100 if new_chunksize < 100
59
72
  new_chunksize
@@ -69,7 +69,7 @@ describe Taps::ClientSession do
69
69
  it "fetches table rows given a chunksize and offset from taps server" do
70
70
  @data = { :header => [ :x, :y ], :data => [ [1, 2], [3, 4] ] }
71
71
  @gzip_data = Taps::Utils.gzip(Marshal.dump(@data))
72
- Taps::Utils.stubs(:calculate_chunksize).with(1000).yields.returns(1000)
72
+ Taps::Utils.stubs(:calculate_chunksize).with(1000).yields(1000).returns(1000)
73
73
 
74
74
  @response = mock('response')
75
75
  @client.session_resource.stubs(:[]).with('tables/mytable/1000?offset=0').returns(mock('table resource'))
data/spec/utils_spec.rb CHANGED
@@ -41,5 +41,9 @@ describe Taps::Utils do
41
41
  Time.stubs(:now).returns(10.0).returns(11.1)
42
42
  Taps::Utils.calculate_chunksize(1000) { }.should == 1100
43
43
  end
44
+
45
+ it "will reset the chunksize to a small value if we got a broken pipe exception" do
46
+ Taps::Utils.calculate_chunksize(1000) { |c| raise Errno::EPIPE if c == 1000; c.should == 100 }.should == 200
47
+ end
44
48
  end
45
49
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ricardochimal-taps
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ricardo Chimal, Jr.
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-03-18 00:00:00 -07:00
13
+ date: 2009-03-31 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -61,7 +61,7 @@ dependencies:
61
61
  requirements:
62
62
  - - ~>
63
63
  - !ruby/object:Gem::Version
64
- version: 2.10.0
64
+ version: 2.11.0
65
65
  version:
66
66
  - !ruby/object:Gem::Dependency
67
67
  name: sqlite3-ruby
@@ -85,20 +85,20 @@ extra_rdoc_files: []
85
85
  files:
86
86
  - spec/base.rb
87
87
  - spec/schema_spec.rb
88
- - spec/utils_spec.rb
89
- - spec/client_session_spec.rb
90
88
  - spec/server_spec.rb
91
- - lib/taps/db_session.rb
89
+ - spec/client_session_spec.rb
90
+ - spec/utils_spec.rb
92
91
  - lib/taps/progress_bar.rb
93
- - lib/taps/cli.rb
92
+ - lib/taps/client_session.rb
93
+ - lib/taps/server.rb
94
+ - lib/taps/utils.rb
94
95
  - lib/taps/adapter_hacks.rb
95
96
  - lib/taps/adapter_hacks/invalid_text_limit.rb
96
97
  - lib/taps/adapter_hacks/non_rails_schema_dump.rb
97
98
  - lib/taps/schema.rb
98
99
  - lib/taps/config.rb
99
- - lib/taps/client_session.rb
100
- - lib/taps/server.rb
101
- - lib/taps/utils.rb
100
+ - lib/taps/cli.rb
101
+ - lib/taps/db_session.rb
102
102
  - README.rdoc
103
103
  - LICENSE
104
104
  - VERSION.yml