Skip to content

Commit

Permalink
internally mysql text fields are the same as blob fields. Needed to
Browse files Browse the repository at this point in the history
add an extra step to taps so it can detect and work around this because
Sequel will make a Sequel::SQL::Blob instance out of text fields.
  • Loading branch information
ricardochimal committed Apr 29, 2009
1 parent 0b1b73d commit d38e7c3
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 4 deletions.
3 changes: 2 additions & 1 deletion lib/taps/client_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,15 @@ def cmd_send_data
count = table.count
order = Taps::Utils.order_by(db, table_name)
chunksize = self.default_chunksize
string_columns = Taps::Utils.incorrect_blobs(db, table_name)

progress = ProgressBar.new(table_name.to_s, count)

offset = 0
loop do
row_size = 0
chunksize = Taps::Utils.calculate_chunksize(chunksize) do |c|
rows = Taps::Utils.format_data(table.order(*order).limit(c, offset).all)
rows = Taps::Utils.format_data(table.order(*order).limit(c, offset).all, string_columns)
break if rows == { }

row_size = rows[:data].size
Expand Down
3 changes: 2 additions & 1 deletion lib/taps/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ class Server < Sinatra::Default
db = session.connection
table = db[params[:table].to_sym]
order = Taps::Utils.order_by(db, params[:table].to_sym)
raw_data = Marshal.dump(Taps::Utils.format_data(table.order(*order).limit(chunk, offset).all))
string_columns = Taps::Utils.incorrect_blobs(db, params[:table].to_sym)
raw_data = Marshal.dump(Taps::Utils.format_data(table.order(*order).limit(chunk, offset).all, string_columns))
gzip_data = Taps::Utils.gzip(raw_data)
response['Taps-Checksum'] = Taps::Utils.checksum(gzip_data).to_s
response['Content-Type'] = "application/octet-stream"
Expand Down
25 changes: 24 additions & 1 deletion lib/taps/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,38 @@ def gunzip(gzip_data)
data
end

def format_data(data)
def format_data(data, string_columns)
return {} if data.size == 0
header = data[0].keys
only_data = data.collect do |row|
row = blobs_to_string(row, string_columns)
header.collect { |h| row[h] }
end
{ :header => header, :data => only_data }
end

# mysql text and blobs fields are handled the same way internally
# this is not true for other databases so we must check if the field is
# actually text and manually convert it back to a string
def incorrect_blobs(db, table)
return [] unless db.class.to_s == "Sequel::MySQL::Database"

columns = []
db.schema[table].each do |data|
column, cdata = data
columns << column if cdata[:db_type] =~ /text/
end
columns
end

def blobs_to_string(row, columns)
return row if columns.size == 0
columns.each do |c|
row[c] = row[c].to_s if row[c].kind_of?(Sequel::SQL::Blob)
end
row
end

def calculate_chunksize(old_chunksize)
chunksize = old_chunksize

Expand Down
13 changes: 12 additions & 1 deletion spec/utils_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
end

it "formats a data hash into one hash that contains an array of headers and an array of array of data" do
Taps::Utils.format_data([ { :x => 1, :y => 1 }, { :x => 2, :y => 2 } ]).should == { :header => [ :x, :y ], :data => [ [1, 1], [2, 2] ] }
Taps::Utils.format_data([ { :x => 1, :y => 1 }, { :x => 2, :y => 2 } ], []).should == { :header => [ :x, :y ], :data => [ [1, 1], [2, 2] ] }
end

it "scales chunksize down slowly when the time delta of the block is just over a second" do
Expand Down Expand Up @@ -45,5 +45,16 @@
it "will reset the chunksize to a small value if we got a broken pipe exception" do
Taps::Utils.calculate_chunksize(1000) { |c| raise Errno::EPIPE if c == 1000; c.should == 100 }.should == 200
end

it "returns a list of columns that are text fields if the database is mysql" do
@db = mock("db")
@db.class.stubs(:to_s).returns("Sequel::MySQL::Database")
@db.stubs(:schema).returns(mock("schema"))
@db.schema.stubs(:[]).with(:mytable).returns([
[:id, { :db_type => "int" }],
[:mytext, { :db_type => "text" }]
])
Taps::Utils.incorrect_blobs(@db, :mytable).should == [:mytext]
end
end

0 comments on commit d38e7c3

Please sign in to comment.