* Removed memcaching for TagImplication (too many latent race conditions)

* Added Post.exact_tag_match to skip normalization/metatag parsing
* Added DelayedJob support for tag alias/implication processing
This commit is contained in:
albert
2011-08-04 19:54:13 -04:00
parent 09d7bba90a
commit e106f70b6d
18 changed files with 123 additions and 162 deletions

View File

@@ -15,6 +15,7 @@ class TagAliasesController < ApplicationController
def create
@tag_alias = TagAlias.create(params[:tag_alias])
@tag_alias.delay.process!
respond_with(@tag_alias, :location => tag_aliases_path(:search => {:id_eq => @tag_alias.id}))
end

View File

@@ -15,6 +15,7 @@ class TagImplicationsController < ApplicationController
def create
@tag_implication = TagImplication.create(params[:tag_implication])
@tag_implication.delay.process!
respond_with(@tag_implication, :location => tag_implications_path(:search => {:id_eq => @tag_implication.id}))
end

View File

@@ -41,6 +41,7 @@ class Post < ActiveRecord::Base
scope :available_for_moderation, lambda {where(["id NOT IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])}
scope :hidden_from_moderation, lambda {where(["id IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])}
scope :tag_match, lambda {|query| Post.tag_match_helper(query)}
scope :exact_tag_match, lambda {|query| Post.exact_tag_match_helper(query)}
scope :positive, where("score > 1")
scope :negative, where("score < -1")
search_methods :tag_match
@@ -501,6 +502,11 @@ class Post < ActiveRecord::Base
relation
end
def exact_tag_match_helper(q)
arel = Post.scoped
add_tag_string_search_relation({:related => [q].flatten, :include => [], :exclude => []}, arel)
end
def tag_match_helper(q)
unless q.is_a?(Hash)

View File

@@ -1,11 +1,7 @@
class TagAlias < ActiveRecord::Base
attr_accessor :creator_ip_addr
after_save :update_posts
after_save :clear_cache
after_save :clear_remote_cache
before_save :clear_all_cache
after_save :update_cache
after_destroy :clear_cache
after_destroy :clear_remote_cache
after_destroy :clear_all_cache
before_validation :initialize_creator, :on => :create
validates_presence_of :creator_id
validates_uniqueness_of :antecedent_name
@@ -25,8 +21,17 @@ class TagAlias < ActiveRecord::Base
alias_hash.values.flatten.uniq
end
def process!
update_column(:status, "processing")
update_posts
update_column(:status, "active")
rescue Exception => e
update_column(:status, "error: #{e}")
end
def initialize_creator
self.creator_id = CurrentUser.user.id
self.creator_ip_addr = CurrentUser.ip_addr
end
def antecedent_tag
@@ -44,6 +49,11 @@ class TagAlias < ActiveRecord::Base
false
end
end
def clear_all_cache
clear_cache
clear_remote_cache
end
def clear_cache
Cache.delete("ta:#{Cache.sanitize(antecedent_name)}")
@@ -60,13 +70,15 @@ class TagAlias < ActiveRecord::Base
end
def update_posts
Post.tag_match(antecedent_name).find_each do |post|
Post.exact_tag_match(antecedent_name).find_each do |post|
escaped_antecedent_name = Regexp.escape(antecedent_name)
fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{consequent_name} ").strip
post.update_attributes(
:tag_string => fixed_tags
)
CurrentUser.scoped(creator, creator_ip_addr) do
post.update_attributes(
:tag_string => fixed_tags
)
end
end
end
end

View File

@@ -1,43 +1,19 @@
class TagImplication < ActiveRecord::Base
before_save :clear_cache
before_save :update_descendant_names
after_save :update_descendant_names_for_parent
after_save :update_cache
after_save :update_posts
after_destroy :clear_cache
after_destroy :clear_remote_cache
belongs_to :creator, :class_name => "User"
before_validation :initialize_creator, :on => :create
validates_presence_of :creator_id
validates_uniqueness_of :antecedent_name, :scope => :consequent_name
validate :absence_of_circular_relation
module CacheMethods
def clear_cache
Cache.delete("ti:#{Cache.sanitize(antecedent_name)}")
@descendants = nil
end
def clear_remote_cache
Danbooru.config.other_server_hosts.each do |server|
Net::HTTP.delete(URI.parse("http://#{server}/tag_implications/#{id}/cache"))
end
end
def update_cache
descendant_names_array
true
end
end
module DescendantMethods
extend ActiveSupport::Concern
module ClassMethods
# assumes names are normalized
def with_descendants(names)
names + Cache.get_multi(names.flatten, "ti") do |name|
([name] + where(["antecedent_name = ?", name]).all.map {|x| x.descendant_names_array}).flatten
end.values.flatten.uniq
(names + where("antecedent_name in (?)", names).map(&:descendant_names_array)).flatten.uniq
end
end
@@ -55,9 +31,7 @@ class TagImplication < ActiveRecord::Base
end
def descendant_names_array
Cache.get("ti:#{Cache.sanitize(antecedent_name)}") do
descendant_names.split(/ /)
end
descendant_names.split(/ /)
end
def update_descendant_names
@@ -93,12 +67,20 @@ class TagImplication < ActiveRecord::Base
end
end
include CacheMethods
include DescendantMethods
include ParentMethods
def initialize_creator
self.creator_id = CurrentUser.user.id
self.creator_ip_addr = CurrentUser.ip_addr
end
def process!
update_column(:status, "processing")
update_posts
update_column(:status, "active")
rescue Exception => e
update_column(:status, "error: #{e}")
end
def absence_of_circular_relation
@@ -110,12 +92,14 @@ class TagImplication < ActiveRecord::Base
end
def update_posts
Post.tag_match(antecedent_name).find_each do |post|
Post.exact_tag_match(antecedent_name).find_each do |post|
escaped_antecedent_name = Regexp.escape(antecedent_name)
fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{antecedent_name} #{descendant_names} ").strip
post.update_attributes(
:tag_string => fixed_tags
)
CurrentUser.scoped(creator, creator_ip_addr) do
post.update_attributes(
:tag_string => fixed_tags
)
end
end
end

View File

@@ -1,40 +0,0 @@
<div id="jquery-test">
<div class="note" id="lots-of-text-1">
Lorem ipsum
</div>
<div class="note" id="lots-of-text-2" style="left: 400px;">
Lorem ipsum
</div>
</div>
<script type="text/javascript">
var body = $("#lots-of-text-2");
body.css({height: "auto", minWidth: 140});
var w = body[0].offsetWidth;
var h = body[0].offsetHeight;
var lo = null;
var hi = null;
var x = null;
var last = null;
if (body[0].scrollWidth <= body[0].clientWidth) {
lo = 20, hi = w
do {
x = (lo+hi)/2
body.css({minWidth: x});
if (body[0].offsetHeight > h) {
lo = x;
} else {
hi = x;
}
} while ((hi - lo) > 4);
if (body[0].offsetHeight > h) {
body.css({minWidth: hi});
}
}
</script>

View File

@@ -1,6 +1,6 @@
<div style="width: 40em; margin: 5em auto; overflow: scroll;">
<div class="section">
<h4>Terms of Service</h4>
<h1>Terms of Service</h1>
<p>By accessing the "<%= Danbooru.config.app_name %>" website ("Site") you agree to the following terms of service. If you do not agree to these terms, then please do not access the Site.</p>
<ul>
@@ -13,13 +13,13 @@
</ul>
<div class="section">
<h6>Post/Comment Limiting</h6>
<h1>Post/Comment Limiting</h1>
<p>You cannot upload a post or comment during the first week of signing up.</p>
<p>After the initial period, you can post up to one comment an hour and a variable number of posts based on how many of your previous uploads were approved or deleted.</p>
</div>
<div class="section">
<h6>Prohibited Content</h6>
<h1>Prohibited Content</h1>
<p>In addition, you may not use the Site to upload any of the following:</p>
<ul>
<li>Non-anime: Photographs of American porn actresses, for example, are prohibited. Photographs of cosplayers, figures, or prominent figures in the industry are acceptable.</li>
@@ -34,7 +34,7 @@
</div>
<div class="section">
<h4>Copyright Infringement</h4>
<h1>Copyright Infringement</h1>
<p>If you believe a post infringes upon your copyright, please send an email to the <%= mail_to Danbooru.config.contact_email, "webmaster", :encode => "hex" %> with the following pieces of information:</p>
<ul>
@@ -45,14 +45,14 @@
</div>
<div class="section">
<h4>Privacy Policy</h4>
<h1>Privacy Policy</h1>
<p>The Site will not disclose the IP address, email address, password, or DMails of any user except to the staff.</p>
<p>The Site is allowed to make public everything else, including but not limited to: uploaded posts, favorited posts, comments, forum posts, wiki edits, and note edits.</p>
</div>
<div>
<h4>Agreement</h4>
<h1>Agreement</h1>
<p>By clicking on the "I Agree" link, you have read all the terms and have agreed to them.</p>
<p><%= link_to("I Agree", params[:url] || "/", :onclick => "Cookie.put('tos', '1')") %> | <%= link_to("Cancel", "/") %></p>
</div>