Class: DB
- Inherits:
-
Object
- Object
- DB
- Defined in:
- backend/app/model/db.rb
Defined Under Namespace
Classes: DBAttempt
Constant Summary
- SUPPORTED_DATABASES =
[ { :pattern => /jdbc:mysql/, :name => "MySQL" }, { :pattern => /jdbc:derby/, :name => "Apache Derby" } ]
Class Method Summary (collapse)
-
+ (Object) after_commit(&block)
-
+ (Object) attempt(&block)
-
+ (Object) backups_dir
-
+ (Object) blobify(s)
-
+ (Object) check_supported(url)
-
+ (Object) concat(s1, s2)
-
+ (Object) connect
-
+ (Boolean) connected?
-
+ (Object) demo_db_backup
-
+ (Object) disconnect
-
+ (Object) ensure_tables_are_utf8(db)
-
+ (Object) expire_backups
-
+ (Object) increase_lock_version_or_fail(obj)
-
+ (Object) is_integrity_violation(exception)
Yeesh.
-
+ (Object) is_retriable_exception(exception, opts = {})
-
+ (Object) jdbc_metadata
-
+ (Boolean) needs_blob_hack?
-
+ (Boolean) needs_savepoint?
-
+ (Object) open(transaction = true, opts = {})
-
+ (Boolean) supports_jasper?
-
+ (Boolean) supports_join_updates?
-
+ (Boolean) supports_mvcc?
-
+ (Object) sysinfo
-
+ (Object) system_metadata
-
+ (Object) transaction(*args)
Class Method Details
+ (Object) after_commit(&block)
105 106 107 108 109 110 111 112 113 |
# File 'backend/app/model/db.rb', line 105 def self.after_commit(&block) if @pool.in_transaction? @pool.after_commit do block.call end else block.call end end |
+ (Object) attempt(&block)
218 219 220 |
# File 'backend/app/model/db.rb', line 218 def self.attempt(&block) DBAttempt.new(block) end |
+ (Object) backups_dir
290 291 292 |
# File 'backend/app/model/db.rb', line 290 def self.backups_dir AppConfig[:backup_directory] end |
+ (Object) blobify(s)
364 365 366 |
# File 'backend/app/model/db.rb', line 364 def self.blobify(s) (@pool.database_type == :derby) ? s.to_sequel_blob : s end |
+ (Object) check_supported(url)
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'backend/app/model/db.rb', line 243 def self.check_supported(url) if !SUPPORTED_DATABASES.any? {|db| url =~ db[:pattern]} msg = "\n=======================================================================\nUNSUPPORTED DATABASE\n=======================================================================\n\nThe database listed in your configuration:\n\n \#{url}\n\nis not officially supported by ArchivesSpace. Although the system may\nstill work, there's no guarantee that future versions will continue to\nwork, or that it will be possible to upgrade without losing your data.\n\nIt is strongly recommended that you run ArchivesSpace against one of\nthese supported databases:\n\n" SUPPORTED_DATABASES.each do |db| msg += " * #{db[:name]}\n" end msg += "\n" msg += "\nTo ignore this (very good) advice, you can set the configuration option:\n\n AppConfig[:allow_unsupported_database] = true\n\n\n=======================================================================\n\n" Log.error(msg) raise "Database not supported" end end |
+ (Object) concat(s1, s2)
369 370 371 372 373 374 375 |
# File 'backend/app/model/db.rb', line 369 def self.concat(s1, s2) if @pool.database_type == :derby "#{s1} || #{s2}" else "CONCAT(#{s1}, #{s2})" end end |
+ (Object) connect
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'backend/app/model/db.rb', line 26 def self.connect if not @pool if !AppConfig[:allow_unsupported_database] check_supported(AppConfig[:db_url]) end begin Log.info("Connecting to database: #{AppConfig[:db_url_redacted]}. Max connections: #{AppConfig[:db_max_connections]}") pool = Sequel.connect(AppConfig[:db_url], :max_connections => AppConfig[:db_max_connections], :test => true, :loggers => (AppConfig[:db_debug_log] ? [Logger.new($stderr)] : []) ) # Test if any tables exist pool[:schema_info].all if pool.database_type == :mysql && AppConfig[:allow_non_utf8_mysql_database] != "true" ensure_tables_are_utf8(pool) end @pool = pool rescue Log.error("DB connection failed: #{$!}") end end end |
+ (Boolean) connected?
93 94 95 |
# File 'backend/app/model/db.rb', line 93 def self.connected? not @pool.nil? end |
+ (Object) demo_db_backup
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'backend/app/model/db.rb', line 318 def self.demo_db_backup # Timestamp must come first here for filenames to sort chronologically this_backup = File.join(backups_dir, "demo_db_backup_#{Time.now.to_i}_#{$$}") Log.info("Writing backup to '#{this_backup}'") @pool.pool.hold do |c| cs = c.prepare_call("CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE(?)") cs.set_string(1, this_backup.to_s) cs.execute cs.close end expire_backups end |
+ (Object) disconnect
238 239 240 |
# File 'backend/app/model/db.rb', line 238 def self.disconnect @pool.disconnect end |
+ (Object) ensure_tables_are_utf8(db)
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'backend/app/model/db.rb', line 56 def self.ensure_tables_are_utf8(db) non_utf8_tables = db[:information_schema__tables]. join(:information_schema__collation_character_set_applicability, :collation_name => :table_collation). filter(:table_schema => Sequel.function(:database)). filter(Sequel.~(:character_set_name => 'utf8')).all unless (non_utf8_tables.empty?) msg = "\nThe following MySQL database tables are not set to use UTF-8 for their character\nencoding:\n\n\#{non_utf8_tables.map {|t| \" * \" + t[:TABLE_NAME]}.join(\"\\n\")}\n\nPlease refer to README.md for instructions on configuring your database to use\nUTF-8.\n\nIf you want to override this restriction (not recommended!) you can set the\nfollowing option in your config.rb file:\n\n AppConfig[:allow_non_utf8_mysql_database] = \"true\"\n\nBut note that ArchivesSpace largely assumes that your data will be UTF-8\nencoded. Running in a non-UTF-8 configuration is not supported.\n\n" Log.warn(msg) raise msg end Log.info("All tables checked and confirmed set to UTF-8. Nice job!") end |
+ (Object) expire_backups
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'backend/app/model/db.rb', line 295 def self.expire_backups backups = [] Dir.foreach(backups_dir) do |filename| if filename =~ /^demo_db_backup_[0-9]+_[0-9]+$/ backups << File.join(backups_dir, filename) end end victims = backups.sort.reverse.drop(AppConfig[:demo_db_backup_number_to_keep]) victims.each do |backup_dir| # Proudly paranoid if File.exists?(File.join(backup_dir, "archivesspace_demo_db", "BACKUP.HISTORY")) Log.info("Expiring old backup: #{backup_dir}") FileUtils.rm_rf(backup_dir) else Log.warn("Too cowardly to delete: #{backup_dir}") end end end |
+ (Object) increase_lock_version_or_fail(obj)
335 336 337 338 339 340 341 342 343 |
# File 'backend/app/model/db.rb', line 335 def self.increase_lock_version_or_fail(obj) updated_rows = obj.class.dataset.filter(:id => obj.id, :lock_version => obj.lock_version). update(:lock_version => obj.lock_version + 1, :system_mtime => Time.now) if updated_rows != 1 raise Sequel::Plugins::OptimisticLocking::Error.new("Couldn't create version of: #{obj}") end end |
+ (Object) is_integrity_violation(exception)
Yeesh.
224 225 226 |
# File 'backend/app/model/db.rb', line 224 def self.is_integrity_violation(exception) (exception.wrapped_exception.cause or exception.wrapped_exception).getSQLState() =~ /^23/ end |
+ (Object) is_retriable_exception(exception, opts = {})
229 230 231 232 233 234 235 |
# File 'backend/app/model/db.rb', line 229 def self.is_retriable_exception(exception, opts = {}) # Transaction was rolled back, but we can retry (exception.instance_of?(RetryTransaction) || (opts[:retry_on_optimistic_locking_fail] && exception.instance_of?(Sequel::Plugins::OptimisticLocking::Error)) || (exception.wrapped_exception.cause or exception.wrapped_exception).getSQLState() =~ /^(40|41)/) end |
+ (Object) jdbc_metadata
173 174 175 176 177 |
# File 'backend/app/model/db.rb', line 173 def self. md = open { |p| p.synchronize { |c| c.getMetaData }} { "databaseProductName" => md.getDatabaseProductName, "databaseProductVersion" => md.getDatabaseProductVersion } end |
+ (Boolean) needs_blob_hack?
360 361 362 |
# File 'backend/app/model/db.rb', line 360 def self.needs_blob_hack? (@pool.database_type == :derby) end |
+ (Boolean) needs_savepoint?
184 185 186 187 188 189 |
# File 'backend/app/model/db.rb', line 184 def self.needs_savepoint? # Postgres needs a savepoint for any statement that might fail # (otherwise the whole transaction becomes invalid). Use a savepoint to # run the happy case, since we're half expecting it to fail. [:postgres].include?(@pool.database_type) end |
+ (Object) open(transaction = true, opts = {})
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'backend/app/model/db.rb', line 116 def self.open(transaction = true, opts = {}) last_err = false retries = opts[:retries] || 10 retries.times do |attempt| begin if transaction self.transaction do return yield @pool end # Sometimes we'll make it to here. That means we threw a # Sequel::Rollback which has been quietly caught. return nil else begin return yield @pool rescue Sequel::Rollback # If we're not in a transaction we can't roll back, but no need to blow up. Log.warn("Sequel::Rollback caught but we're not inside of a transaction") return nil end end rescue Sequel::DatabaseDisconnectError => e # MySQL might have been restarted. last_err = e Log.info("Connecting to the database failed. Retrying...") sleep(opts[:db_failed_retry_delay] || 3) rescue Sequel::DatabaseError => e if (attempt + 1) < retries && is_retriable_exception(e, opts) && transaction Log.info("Retrying transaction after retriable exception (#{e})") sleep(opts[:retry_delay] || 1) else raise e end end end if last_err Log.error("Failed to connect to the database") Log.exception(last_err) raise "Failed to connect to the database: #{last_err}" end end |
+ (Boolean) supports_jasper?
345 346 347 |
# File 'backend/app/model/db.rb', line 345 def self.supports_jasper? ![:derby, :h2].include?(@pool.database_type) end |
+ (Boolean) supports_join_updates?
355 356 357 |
# File 'backend/app/model/db.rb', line 355 def self.supports_join_updates? ![:derby, :h2].include?(@pool.database_type) end |
+ (Boolean) supports_mvcc?
350 351 352 |
# File 'backend/app/model/db.rb', line 350 def self.supports_mvcc? ![:derby, :h2].include?(@pool.database_type) end |
+ (Object) sysinfo
168 169 170 |
# File 'backend/app/model/db.rb', line 168 def self.sysinfo .merge() end |
+ (Object) system_metadata
179 180 181 182 |
# File 'backend/app/model/db.rb', line 179 def self. RbConfig.const_get("CONFIG").select { |key| ['host_os', 'host_cpu', 'build', 'ruby_version'].include? key } end |
+ (Object) transaction(*args)
98 99 100 101 102 |
# File 'backend/app/model/db.rb', line 98 def self.transaction(*args) @pool.transaction(*args) do yield end end |