From 28cae2b5e722222c03a3ba0ed8139b128cd034b9 Mon Sep 17 00:00:00 2001 From: Andy Atkinson Date: Fri, 20 Sep 2024 22:06:05 -0500 Subject: [PATCH] Adding Solid Cache Adding DB migrations for solid cache Adding an demonstration patch to create READ ONLY transactions --- Gemfile | 2 + Gemfile.lock | 27 +++--- config/environments/development.rb | 2 +- config/solid_cache.yml | 15 ++++ ..._create_solid_cache_entries.solid_cache.rb | 12 +++ ...size_to_solid_cache_entries.solid_cache.rb | 11 +++ ...ints_to_solid_cache_entries.solid_cache.rb | 14 +++ ...ex_from_solid_cache_entries.solid_cache.rb | 10 +++ db/structure.sql | 80 ++++++++++++++++++ erd.pdf | Bin 53922 -> 53922 bytes lib/patches/active_record_patches.rb | 15 ++++ 11 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 config/solid_cache.yml create mode 100644 db/migrate/20240918204932_create_solid_cache_entries.solid_cache.rb create mode 100644 db/migrate/20240918204933_add_key_hash_and_byte_size_to_solid_cache_entries.solid_cache.rb create mode 100644 db/migrate/20240918204934_add_key_hash_and_byte_size_indexes_and_null_constraints_to_solid_cache_entries.solid_cache.rb create mode 100644 db/migrate/20240918204935_remove_key_index_from_solid_cache_entries.solid_cache.rb create mode 100644 lib/patches/active_record_patches.rb diff --git a/Gemfile b/Gemfile index 591d8b6..58a9818 100644 --- a/Gemfile +++ b/Gemfile @@ -41,3 +41,5 @@ group :development, :test do gem 'database_consistency' gem 'dotenv-rails' # Manage .env end + +gem "solid_cache", "~> 0.7.0" diff --git a/Gemfile.lock b/Gemfile.lock index 0ff1f88..89a89bf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -106,7 +106,7 @@ GEM code_analyzer (0.5.5) sexp_processor coderay (1.1.3) - concurrent-ruby (1.3.3) + concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) csv (3.3.0) @@ -151,7 +151,7 @@ GEM google-protobuf (4.27.2-x86_64-linux) bigdecimal rake (>= 13) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) importmap-rails (1.2.3) actionpack (>= 6.0.0) @@ -177,7 +177,7 @@ GEM memory_profiler (1.0.2) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.24.1) + minitest (5.25.1) mutex_m (0.2.0) net-http (0.4.1) uri @@ -191,13 +191,13 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.6-aarch64-linux) + nokogiri (1.16.7-aarch64-linux) racc (~> 1.4) - nokogiri (1.16.6-arm64-darwin) + nokogiri (1.16.7-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.6-x86_64-darwin) + nokogiri (1.16.7-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.6-x86_64-linux) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) pg (1.5.6) pg_query (5.1.0) @@ -213,7 +213,7 @@ GEM stringio puma (6.4.2) nio4r (~> 2.0) - racc (1.8.0) + racc (1.8.1) rack (3.1.7) rack-session (2.0.0) rack (>= 3.0.0) @@ -270,7 +270,7 @@ GEM rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) - reline (0.5.9) + reline (0.5.10) io-console (~> 0.5) require_all (3.0.0) rexml (3.3.6) @@ -285,6 +285,10 @@ GEM activerecord (>= 4.0.0) railties (>= 4.0.0) sexp_processor (4.17.2) + solid_cache (0.7.0) + activejob (>= 7) + activerecord (>= 7) + railties (>= 7) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -298,7 +302,7 @@ GEM strscan (3.1.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - thor (1.3.1) + thor (1.3.2) timeout (0.4.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -310,7 +314,7 @@ GEM websocket-extensions (0.1.5) whenever (1.0.0) chronic (>= 0.6.3) - zeitwerk (2.6.16) + zeitwerk (2.6.18) PLATFORMS aarch64-linux @@ -352,6 +356,7 @@ DEPENDENCIES rails-pg-extras rails_best_practices scenic + solid_cache (~> 0.7.0) sprockets-rails (~> 3.4) strong_migrations whenever (~> 1.0) diff --git a/config/environments/development.rb b/config/environments/development.rb index a9c3707..cc85b93 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -18,7 +18,7 @@ config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true - config.cache_store = :memory_store + config.cache_store = :solid_cache_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } diff --git a/config/solid_cache.yml b/config/solid_cache.yml new file mode 100644 index 0000000..3f83ff1 --- /dev/null +++ b/config/solid_cache.yml @@ -0,0 +1,15 @@ +default: &default + database: <%= Rails.env %> + store_options: + max_age: <%= 1.week.to_i %> + max_size: <%= 256.megabytes %> + namespace: <%= Rails.env %> + +development: + <<: *default + +test: + <<: *default + +production: + <<: *default diff --git a/db/migrate/20240918204932_create_solid_cache_entries.solid_cache.rb b/db/migrate/20240918204932_create_solid_cache_entries.solid_cache.rb new file mode 100644 index 0000000..4ff1fbd --- /dev/null +++ b/db/migrate/20240918204932_create_solid_cache_entries.solid_cache.rb @@ -0,0 +1,12 @@ +# This migration comes from solid_cache (originally 20230724121448) +class CreateSolidCacheEntries < ActiveRecord::Migration[7.0] + def change + create_table :solid_cache_entries do |t| + t.binary :key, null: false, limit: 1024 + t.binary :value, null: false, limit: 512.megabytes + t.datetime :created_at, null: false + + t.index :key, unique: true + end + end +end diff --git a/db/migrate/20240918204933_add_key_hash_and_byte_size_to_solid_cache_entries.solid_cache.rb b/db/migrate/20240918204933_add_key_hash_and_byte_size_to_solid_cache_entries.solid_cache.rb new file mode 100644 index 0000000..32d1739 --- /dev/null +++ b/db/migrate/20240918204933_add_key_hash_and_byte_size_to_solid_cache_entries.solid_cache.rb @@ -0,0 +1,11 @@ +# This migration comes from solid_cache (originally 20240108155507) +class AddKeyHashAndByteSizeToSolidCacheEntries < ActiveRecord::Migration[7.0] + def change + safety_assured do + change_table :solid_cache_entries do |t| + t.column :key_hash, :integer, null: true, limit: 8 + t.column :byte_size, :integer, null: true, limit: 4 + end + end + end +end diff --git a/db/migrate/20240918204934_add_key_hash_and_byte_size_indexes_and_null_constraints_to_solid_cache_entries.solid_cache.rb b/db/migrate/20240918204934_add_key_hash_and_byte_size_indexes_and_null_constraints_to_solid_cache_entries.solid_cache.rb new file mode 100644 index 0000000..c28a5c1 --- /dev/null +++ b/db/migrate/20240918204934_add_key_hash_and_byte_size_indexes_and_null_constraints_to_solid_cache_entries.solid_cache.rb @@ -0,0 +1,14 @@ +# This migration comes from solid_cache (originally 20240110111600) +class AddKeyHashAndByteSizeIndexesAndNullConstraintsToSolidCacheEntries < ActiveRecord::Migration[7.0] + def change + safety_assured do + change_table :solid_cache_entries, bulk: true do |t| + t.change_null :key_hash, false + t.change_null :byte_size, false + t.index :key_hash, unique: true + t.index [:key_hash, :byte_size] + t.index :byte_size + end + end + end +end diff --git a/db/migrate/20240918204935_remove_key_index_from_solid_cache_entries.solid_cache.rb b/db/migrate/20240918204935_remove_key_index_from_solid_cache_entries.solid_cache.rb new file mode 100644 index 0000000..0a557b1 --- /dev/null +++ b/db/migrate/20240918204935_remove_key_index_from_solid_cache_entries.solid_cache.rb @@ -0,0 +1,10 @@ +# This migration comes from solid_cache (originally 20240110111702) +class RemoveKeyIndexFromSolidCacheEntries < ActiveRecord::Migration[7.0] + def change + safety_assured do + change_table :solid_cache_entries do |t| + t.remove_index :key, unique: true + end + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 8da33d7..2d908f1 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -27,6 +27,9 @@ DROP INDEX IF EXISTS rideshare.index_trips_on_driver_id; DROP INDEX IF EXISTS rideshare.index_trip_requests_on_start_location_id; DROP INDEX IF EXISTS rideshare.index_trip_requests_on_rider_id; DROP INDEX IF EXISTS rideshare.index_trip_requests_on_end_location_id; +DROP INDEX IF EXISTS rideshare.index_solid_cache_entries_on_key_hash_and_byte_size; +DROP INDEX IF EXISTS rideshare.index_solid_cache_entries_on_key_hash; +DROP INDEX IF EXISTS rideshare.index_solid_cache_entries_on_byte_size; DROP INDEX IF EXISTS rideshare.index_locations_on_address; DROP INDEX IF EXISTS rideshare.index_fast_search_results_on_driver_id; ALTER TABLE IF EXISTS ONLY rideshare.vehicles DROP CONSTRAINT IF EXISTS vehicles_pkey; @@ -35,6 +38,7 @@ ALTER TABLE IF EXISTS ONLY rideshare.users DROP CONSTRAINT IF EXISTS users_pkey; ALTER TABLE IF EXISTS ONLY rideshare.trips DROP CONSTRAINT IF EXISTS trips_pkey; ALTER TABLE IF EXISTS ONLY rideshare.trip_requests DROP CONSTRAINT IF EXISTS trip_requests_pkey; ALTER TABLE IF EXISTS ONLY rideshare.trip_positions DROP CONSTRAINT IF EXISTS trip_positions_pkey; +ALTER TABLE IF EXISTS ONLY rideshare.solid_cache_entries DROP CONSTRAINT IF EXISTS solid_cache_entries_pkey; ALTER TABLE IF EXISTS ONLY rideshare.schema_migrations DROP CONSTRAINT IF EXISTS schema_migrations_pkey; ALTER TABLE IF EXISTS ONLY rideshare.vehicle_reservations DROP CONSTRAINT IF EXISTS non_overlapping_vehicle_registration; ALTER TABLE IF EXISTS ONLY rideshare.locations DROP CONSTRAINT IF EXISTS locations_pkey; @@ -46,6 +50,7 @@ ALTER TABLE IF EXISTS rideshare.users ALTER COLUMN id DROP DEFAULT; ALTER TABLE IF EXISTS rideshare.trips ALTER COLUMN id DROP DEFAULT; ALTER TABLE IF EXISTS rideshare.trip_requests ALTER COLUMN id DROP DEFAULT; ALTER TABLE IF EXISTS rideshare.trip_positions ALTER COLUMN id DROP DEFAULT; +ALTER TABLE IF EXISTS rideshare.solid_cache_entries ALTER COLUMN id DROP DEFAULT; ALTER TABLE IF EXISTS rideshare.locations ALTER COLUMN id DROP DEFAULT; DROP SEQUENCE IF EXISTS rideshare.vehicles_id_seq; DROP TABLE IF EXISTS rideshare.vehicles; @@ -57,6 +62,8 @@ DROP SEQUENCE IF EXISTS rideshare.trip_requests_id_seq; DROP TABLE IF EXISTS rideshare.trip_requests; DROP SEQUENCE IF EXISTS rideshare.trip_positions_id_seq; DROP TABLE IF EXISTS rideshare.trip_positions; +DROP SEQUENCE IF EXISTS rideshare.solid_cache_entries_id_seq; +DROP TABLE IF EXISTS rideshare.solid_cache_entries; DROP VIEW IF EXISTS rideshare.search_results; DROP TABLE IF EXISTS rideshare.schema_migrations; DROP SEQUENCE IF EXISTS rideshare.locations_id_seq; @@ -314,6 +321,39 @@ CREATE VIEW rideshare.search_results AS ORDER BY (count(t.rating)) DESC; +-- +-- Name: solid_cache_entries; Type: TABLE; Schema: rideshare; Owner: - +-- + +CREATE TABLE rideshare.solid_cache_entries ( + id bigint NOT NULL, + key bytea NOT NULL, + value bytea NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + key_hash bigint NOT NULL, + byte_size integer NOT NULL +); + + +-- +-- Name: solid_cache_entries_id_seq; Type: SEQUENCE; Schema: rideshare; Owner: - +-- + +CREATE SEQUENCE rideshare.solid_cache_entries_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: solid_cache_entries_id_seq; Type: SEQUENCE OWNED BY; Schema: rideshare; Owner: - +-- + +ALTER SEQUENCE rideshare.solid_cache_entries_id_seq OWNED BY rideshare.solid_cache_entries.id; + + -- -- Name: trip_positions; Type: TABLE; Schema: rideshare; Owner: - -- @@ -491,6 +531,13 @@ ALTER SEQUENCE rideshare.vehicles_id_seq OWNED BY rideshare.vehicles.id; ALTER TABLE ONLY rideshare.locations ALTER COLUMN id SET DEFAULT nextval('rideshare.locations_id_seq'::regclass); +-- +-- Name: solid_cache_entries id; Type: DEFAULT; Schema: rideshare; Owner: - +-- + +ALTER TABLE ONLY rideshare.solid_cache_entries ALTER COLUMN id SET DEFAULT nextval('rideshare.solid_cache_entries_id_seq'::regclass); + + -- -- Name: trip_positions id; Type: DEFAULT; Schema: rideshare; Owner: - -- @@ -573,6 +620,14 @@ ALTER TABLE ONLY rideshare.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); +-- +-- Name: solid_cache_entries solid_cache_entries_pkey; Type: CONSTRAINT; Schema: rideshare; Owner: - +-- + +ALTER TABLE ONLY rideshare.solid_cache_entries + ADD CONSTRAINT solid_cache_entries_pkey PRIMARY KEY (id); + + -- -- Name: trip_positions trip_positions_pkey; Type: CONSTRAINT; Schema: rideshare; Owner: - -- @@ -635,6 +690,27 @@ CREATE UNIQUE INDEX index_fast_search_results_on_driver_id ON rideshare.fast_sea CREATE UNIQUE INDEX index_locations_on_address ON rideshare.locations USING btree (address); +-- +-- Name: index_solid_cache_entries_on_byte_size; Type: INDEX; Schema: rideshare; Owner: - +-- + +CREATE INDEX index_solid_cache_entries_on_byte_size ON rideshare.solid_cache_entries USING btree (byte_size); + + +-- +-- Name: index_solid_cache_entries_on_key_hash; Type: INDEX; Schema: rideshare; Owner: - +-- + +CREATE UNIQUE INDEX index_solid_cache_entries_on_key_hash ON rideshare.solid_cache_entries USING btree (key_hash); + + +-- +-- Name: index_solid_cache_entries_on_key_hash_and_byte_size; Type: INDEX; Schema: rideshare; Owner: - +-- + +CREATE INDEX index_solid_cache_entries_on_key_hash_and_byte_size ON rideshare.solid_cache_entries USING btree (key_hash, byte_size); + + -- -- Name: index_trip_requests_on_end_location_id; Type: INDEX; Schema: rideshare; Owner: - -- @@ -776,6 +852,10 @@ ALTER TABLE ONLY rideshare.trip_requests SET search_path TO rideshare; INSERT INTO "schema_migrations" (version) VALUES +('20240918204935'), +('20240918204934'), +('20240918204933'), +('20240918204932'), ('20231220043547'), ('20231218215836'), ('20231213045957'), diff --git a/erd.pdf b/erd.pdf index cceb3c03256815d06b7cce0821e5bd3b3ba1f760..218ebad228acb888d48a85b155126027e736b819 100644 GIT binary patch delta 296 zcmV+@0oVSbr30d+1F-eae@|eu{S~)k8J9{@X?NunJ2l1#$OQdI&MNLNSuW z(*5>LbhVVg!2EcV_l5~UoFqd+oCskOI!TUQ7CS|O;Cdf9f|_<*IRJvUzE$`@1cC;i zGb+V2XoSx3I8W44v=ieJE~C8^2>mekBe*xMM|B8-nRb$nx1K3qf5^`BmTx4dx)(!5 zHHTXrA`-=9Z)!vmlE0ATnGkO^`HO`oV{PYaD!I*Jlg;3rw>>?H9}}0Dw@-7VX|{zP zw2>>soBk}tG@>YMWBbKprYpJ_D(Rp`>&5OXeub73U%S$%D*oLw-keVsn#`6rT!~3C uuCUuYFJ_SGCAuQ14eq)vJ+O&J& z6_Wirr#Yv*pp4V1;7_!Cq%@sO{$k-FSjYXNuqx(=$p-MIE?R8OPl!vydtO#pE?0Bt z)(5!*pY;c8`VMs+hd7TO1D()0P%B#3MK5`q@C&@{)imvbYOlVvRHwr>!jL)glX9lF uQaKc}=Q%7&KSp=q6$=0A?SvO!rn$EZ7r2)TqF+WHZt|0{%oDR4(T4$jYLX)W diff --git a/lib/patches/active_record_patches.rb b/lib/patches/active_record_patches.rb new file mode 100644 index 0000000..e425576 --- /dev/null +++ b/lib/patches/active_record_patches.rb @@ -0,0 +1,15 @@ +# +# Replace begin_db_transaction to ONLY create READ ONLY +# transactions. This would be a bad idea in a real app, which would +# need to read and write data. This is only for a demonstration. +# + +module Patches::ActiveRecordPatches + module ::ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements + def begin_db_transaction + # Replaces: + # internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false) + internal_execute("BEGIN", "TRANSACTION READ ONLY", allow_retry: true, materialize_transactions: false) + end + end +end