From 059772cce93c47677671755400202be5581822a5 Mon Sep 17 00:00:00 2001 From: Darin McBride Date: Tue, 2 Jun 2015 22:53:59 -0600 Subject: [PATCH] Don't store vote totals in the propositions table, all the votes are indexed well and can be queried very quickly. --- lib/Lacuna/DB/Result/Empire.pm | 2 +- lib/Lacuna/DB/Result/Propositions.pm | 80 ++++++++++++++++++---------- var/upgrades/3.0912.sql | 1 + 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/lib/Lacuna/DB/Result/Empire.pm b/lib/Lacuna/DB/Result/Empire.pm index 5b8c2ee8..3e1256b6 100644 --- a/lib/Lacuna/DB/Result/Empire.pm +++ b/lib/Lacuna/DB/Result/Empire.pm @@ -465,7 +465,7 @@ sub get_latest_message_id { },{ order_by => { -desc => 'date_sent' }, })->first; - my $message_id = defined $message ? $message->id : 0; + my $message_id = defined $message ? $message->id : undef; return $message_id; } diff --git a/lib/Lacuna/DB/Result/Propositions.pm b/lib/Lacuna/DB/Result/Propositions.pm index 1d97eab9..32160084 100644 --- a/lib/Lacuna/DB/Result/Propositions.pm +++ b/lib/Lacuna/DB/Result/Propositions.pm @@ -12,9 +12,6 @@ __PACKAGE__->table('propositions'); __PACKAGE__->add_columns( name => { data_type => 'varchar', size => 30, is_nullable => 0 }, station_id => { data_type => 'int', size => 11, is_nullable => 0 }, - votes_needed => { data_type => 'int', is_nullable => 0, default_value => 1 }, - votes_yes => { data_type => 'int', is_nullable => 0, default_value => 0 }, - votes_no => { data_type => 'int', is_nullable => 0, default_value => 0 }, description => { data_type => 'text', is_nullable => 1 }, type => { data_type => 'varchar', size => 30, is_nullable => 0 }, scratch => { data_type => 'mediumblob', is_nullable => 1, 'serializer_class' => 'JSON' }, @@ -63,6 +60,33 @@ sub sqlt_deploy_hook { $sqlt_table->add_index(name => 'idx_status_date_ends', fields => ['status','date_ends']); } +has votes_needed => ( + is => 'ro', + lazy => 1, + default => sub { + my $self = shift; + int( ($self->station->alliance->members->count + 1) / 2); + } +); + +has votes_yes => ( + is => 'ro', + lazy => 1, + default => sub { + my $self = shift; + $self->votes->search({vote => 1})->count; + } +); + +has votes_no => ( + is => 'ro', + lazy => 1, + default => sub { + my $self = shift; + $self->votes->search({vote => 0})->count; + } +); + sub cast_vote { my ($self, $empire, $vote) = @_; unless ($self->status eq 'Pending') { @@ -76,13 +100,6 @@ sub cast_vote { empire_id => $empire->id, vote => $vote, })->insert; - if ($vote) { - $self->votes_yes( $self->votes_yes + 1 ); - } - else { - $self->votes_no( $self->votes_no + 1 ); - } - $self->update; $self->check_status; } @@ -95,29 +112,37 @@ before delete => sub { sub check_status { my $self = shift; my $cache = Lacuna->cache; - return $self if $cache->get('proposition_recently_completed', $self->id); if ($self->status eq 'Pending') { - $self->votes_needed( int( ( $self->station->alliance->members->count + 1 ) / 2 ) ); - } - if ($self->status ne 'Pending') { - } - elsif ($self->votes_yes >= $self->votes_needed) { - $cache->set('proposition_recently_completed', $self->id, 30); - $self->pass; - } - elsif ($self->votes_no >= $self->votes_needed) { - $cache->set('proposition_recently_completed', $self->id, 30); - $self->fail; - } - elsif ($self->date_ends->epoch < time()) { - $cache->set('proposition_recently_completed', $self->id, 30); - $self->pass; + # cache check as close as possible to cache set to reduce chance + # (but not eliminate chance) of race condition + if ($self->votes_yes >= $self->votes_needed) { + return $self if $cache->get('proposition_recently_completed', $self->id); + $cache->set('proposition_recently_completed', $self->id, 30); + $self->pass; + } + elsif ($self->votes_no >= $self->votes_needed) { + return $self if $cache->get('proposition_recently_completed', $self->id); + $cache->set('proposition_recently_completed', $self->id, 30); + $self->fail; + } + elsif ($self->date_ends->epoch < time()) { + return $self if $cache->get('proposition_recently_completed', $self->id); + $cache->set('proposition_recently_completed', $self->id, 30); + $self->time_is_up; + } + $self->update; } - $self->update; return $self; } +# allow some propositions to auto-fail by overriding this. +sub time_is_up +{ + my ($self) = @_; + $self->pass; +} + sub pass { my $self = shift; $self->station->alliance->send_predefined_message( @@ -164,7 +189,6 @@ has fail_extra_message => ( before insert => sub { my $self = shift; - $self->votes_needed( int( ( $self->station->alliance->members->count + 1 ) / 2 ) ); $self->date_ends( DateTime->now->add(hours => 72) ); }; diff --git a/var/upgrades/3.0912.sql b/var/upgrades/3.0912.sql index a978e733..8580703a 100644 --- a/var/upgrades/3.0912.sql +++ b/var/upgrades/3.0912.sql @@ -1 +1,2 @@ alter table body add column notes text; +alter table propositions drop column votes_yes, drop column votes_no, drop column votes_needed; -- 2.51.2