diff --git a/Gemfile b/Gemfile index 64d62a3..2eb052d 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,12 @@ gem "rails", "4.0.2" # Use mysql2 as the database for Active Record gem "mysql2", ">= 0.3.14" +# Use PostgreSQL as the database for Active Record +# gem "pg" +# +# NOTE: If you use PostgreSQL, you must still leave enabled the above mysql2 gem +# for Sphinx full text search to function. + # Use Rails3-style mass assignment security gem "protected_attributes" diff --git a/app/models/keystore.rb b/app/models/keystore.rb index 123e8da..8f9caf5 100644 --- a/app/models/keystore.rb +++ b/app/models/keystore.rb @@ -1,21 +1,29 @@ class Keystore < ActiveRecord::Base - validates_presence_of :key + self.primary_key = "key" - attr_accessible nil + validates_presence_of :key def self.get(key) self.where(:key => key).first end + def self.value_for(key) + self.where(:key => key).first.try(:value) + end + def self.put(key, value) if Keystore.connection.adapter_name == "SQLite" Keystore.connection.execute("INSERT OR REPLACE INTO " << "#{Keystore.table_name} (`key`, `value`) VALUES " << "(#{q(key)}, #{q(value)})") - else + elsif Keystore.connection.adapter_name =~ /Mysql/ Keystore.connection.execute("INSERT INTO #{Keystore.table_name} (" + "`key`, `value`) VALUES (#{q(key)}, #{q(value)}) ON DUPLICATE KEY " + "UPDATE `value` = #{q(value)}") + else + kv = self.find_or_create_key_for_update(key, value) + kv.value = value + kv.save! end true @@ -26,8 +34,6 @@ class Keystore < ActiveRecord::Base end def self.incremented_value_for(key, amount = 1) - new_value = nil - Keystore.transaction do if Keystore.connection.adapter_name == "SQLite" Keystore.connection.execute("INSERT OR IGNORE INTO " << @@ -35,16 +41,36 @@ class Keystore < ActiveRecord::Base "(#{q(key)}, 0)") Keystore.connection.execute("UPDATE #{Keystore.table_name} " << "SET `value` = `value` + #{q(amount)} WHERE `key` = #{q(key)}") - else + elsif Keystore.connection.adapter_name =~ /Mysql/ Keystore.connection.execute("INSERT INTO #{Keystore.table_name} (" + "`key`, `value`) VALUES (#{q(key)}, #{q(amount)}) ON DUPLICATE KEY " + "UPDATE `value` = `value` + #{q(amount)}") + else + kv = self.find_or_create_key_for_update(key, 0) + kv.value = kv.value.to_i + amount + kv.save! + return kv.value end - new_value = self.value_for(key) + self.value_for(key) end + end - return new_value + def self.find_or_create_key_for_update(key, init = nil) + loop do + kv = self.lock(true).where(:key => key).first + return kv if kv + + begin + self.create! do |kv| + kv.key = key + kv.value = init + kv.save! + end + rescue ActiveRecord::RecordNotUnique + nil + end + end end def self.decrement_value_for(key, amount = -1) @@ -54,8 +80,4 @@ class Keystore < ActiveRecord::Base def self.decremented_value_for(key, amount = -1) self.incremented_value_for(key, amount) end - - def self.value_for(key) - self.get(key).try(:value) - end end diff --git a/db/migrate/20120816203248_keystore_bigint.rb b/db/migrate/20120816203248_keystore_bigint.rb index f3c1d31..4348762 100644 --- a/db/migrate/20120816203248_keystore_bigint.rb +++ b/db/migrate/20120816203248_keystore_bigint.rb @@ -1,6 +1,6 @@ class KeystoreBigint < ActiveRecord::Migration def up - execute("ALTER TABLE keystores CHANGE value value BIGINT") + change_column :keystores, :value, :integer, :limit => 8 end def down diff --git a/db/migrate/20130526164230_change_tables_to_utf8mb4.rb b/db/migrate/20130526164230_change_tables_to_utf8mb4.rb index fb30235..6728b3e 100644 --- a/db/migrate/20130526164230_change_tables_to_utf8mb4.rb +++ b/db/migrate/20130526164230_change_tables_to_utf8mb4.rb @@ -1,5 +1,7 @@ class ChangeTablesToUtf8mb4 < ActiveRecord::Migration def up + return if connection.adapter_name !~ /Mysql/ + [ "comments", "invitations", "messages", "moderations", "stories", "users" ].each do |t| execute("alter table #{t} convert to character set utf8mb4") end