Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ivan Ivlev
bugzilla
Commits
a11f4823
Commit
a11f4823
authored
Dec 19, 2013
by
Byron Jones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 237498: Add memcached integration
r=dkl, a=sgreen
parent
eda2c8f8
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
568 additions
and
34 deletions
+568
-34
Bugzilla.pm
Bugzilla.pm
+88
-11
Bug.pm
Bugzilla/Bug.pm
+3
-3
Memcached.pm
Bugzilla/Config/Memcached.pm
+32
-0
DB.pm
Bugzilla/DB.pm
+12
-5
Requirements.pm
Bugzilla/Install/Requirements.pm
+9
-0
Memcached.pm
Bugzilla/Memcached.pm
+346
-0
Object.pm
Bugzilla/Object.pm
+52
-15
checksetup.pl
checksetup.pl
+3
-0
memcached.html.tmpl
template/en/default/admin/params/memcached.html.tmpl
+22
-0
strings.txt.pl
template/en/default/setup/strings.txt.pl
+1
-0
No files found.
Bugzilla.pm
View file @
a11f4823
...
...
@@ -19,23 +19,24 @@ BEGIN {
}
}
use
Bugzilla::
Config
;
use
Bugzilla::
Constants
;
use
Bugzilla::
Auth
;
use
Bugzilla::Auth::Persist::
Cookie
;
use
Bugzilla::
CGI
;
use
Bugzilla::
Extension
;
use
Bugzilla::
Config
;
use
Bugzilla::
Constants
;
use
Bugzilla::
DB
;
use
Bugzilla::
Error
;
use
Bugzilla::
Extension
;
use
Bugzilla::
Field
;
use
Bugzilla::
Flag
;
use
Bugzilla::Install::
Localconfig
qw(read_localconfig)
;
use
Bugzilla::Install::
Requirements
qw(OPTIONAL_MODULES)
;
use
Bugzilla::Install::
Util
qw(init_console include_languages)
;
use
Bugzilla::
Memcached
;
use
Bugzilla::
Template
;
use
Bugzilla::
Token
;
use
Bugzilla::
User
;
use
Bugzilla::
Error
;
use
Bugzilla::
Util
;
use
Bugzilla::
Field
;
use
Bugzilla::
Flag
;
use
Bugzilla::
Token
;
use
File::
Basename
;
use
File::Spec::
Functions
;
...
...
@@ -641,6 +642,12 @@ sub process_cache {
return
$_process_cache
;
}
# This is a memcached wrapper, which provides cross-process and cross-system
# caching.
sub
memcached
{
return
$_
[
0
]
->
process_cache
->
{
memcached
}
||=
Bugzilla::
Memcached
->
_new
();
}
# Private methods
# Per-process cleanup. Note that this is a plain subroutine, not a method,
...
...
@@ -949,17 +956,89 @@ this Bugzilla installation.
Tells you whether or not a specific feature is enabled. For names
of features, see C<OPTIONAL_MODULES> in C<Bugzilla::Install::Requirements>.
=back
=head1 B<CACHING>
Bugzilla has several different caches available which provide different
capabilities and lifetimes.
The keys of all caches are unregulated; use of prefixes is suggested to avoid
collisions.
=over
=item B<Request Cache>
The request cache is a hashref which supports caching any perl variable for the
duration of the current request. At the end of the current request the contents
of this cache are cleared.
Examples of its use include caching objects to avoid re-fetching the same data
from the database, and passing data between otherwise unconnected parts of
Bugzilla.
=over
=item C<request_cache>
Returns a hashref which can be checked and modified to store any perl variable
for the duration of the current request.
=item C<clear_request_cache>
Removes all entries from the C<request_cache>.
=back
=head1 B<Methods in need of POD>
=item B<Process Cache>
The process cache is a hashref which support caching of any perl variable. If
Bugzilla is configured to run using Apache mod_perl, the contents of this cache
are persisted across requests for the lifetime of the Apache worker process
(which varies depending on the SizeLimit configuration in mod_perl.pl).
If Bugzilla isn't running under mod_perl, the process cache's contents are
cleared at the end of the request.
The process cache is only suitable for items which never change while Bugzilla
is running (for example the path where Bugzilla is installed).
=over
=item process_cache
=item C<process_cache>
Returns a hashref which can be checked and modified to store any perl variable
for the duration of the current process (mod_perl) or request (mod_cgi).
=back
=item B<Memcached>
If Memcached is installed and configured, Bugzilla can use it to cache data
across requests and between webheads. Unlike the request and process caches,
only scalars, hashrefs, and arrayrefs can be stored in Memcached.
Memcached integration is only required for large installations of Bugzilla -- if
you have multiple webheads then configuring Memcached is recommended.
=over
=item C<memcached>
Returns a C<Bugzilla::Memcached> object. An object is always returned even if
Memcached is not available.
See the documentation for the C<Bugzilla::Memcached> module for more
information.
=back
=back
=head1 B<Methods in need of POD>
=over
=item init_page
...
...
@@ -971,8 +1050,6 @@ Removes all entries from the C<request_cache>.
=item active_custom_fields
=item request_cache
=item has_flags
=back
Bugzilla/Bug.pm
View file @
a11f4823
...
...
@@ -353,9 +353,9 @@ sub initialize {
$_
[
0
]
->
_create_cf_accessors
();
}
sub
cache_key
{
sub
object_
cache_key
{
my
$class
=
shift
;
my
$key
=
$class
->
SUPER::
cache_key
(
@_
)
my
$key
=
$class
->
SUPER::
object_
cache_key
(
@_
)
||
return
;
return
$key
.
','
.
Bugzilla
->
user
->
id
;
}
...
...
@@ -4422,7 +4422,7 @@ Ensures the accessors for custom fields are always created.
=
item
set_op_sys
=
item
cache_key
=
item
object_
cache_key
=
item
bug_group
...
...
Bugzilla/Config/Memcached.pm
0 → 100644
View file @
a11f4823
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package
Bugzilla::Config::
Memcached
;
use
5.10.1
;
use
strict
;
use
Bugzilla::Config::
Common
;
our
$sortkey
=
1550
;
sub
get_param_list
{
return
(
{
name
=>
'memcached_servers'
,
type
=>
't'
,
default
=>
''
},
{
name
=>
'memcached_namespace'
,
type
=>
't'
,
default
=>
'bugzilla:'
,
},
);
}
1
;
Bugzilla/DB.pm
View file @
a11f4823
...
...
@@ -1362,14 +1362,19 @@ sub _bz_real_schema {
my
(
$self
)
=
@_
;
return
$self
->
{
private_real_schema
}
if
exists
$self
->
{
private_real_schema
};
my
(
$data
,
$version
)
=
$self
->
selectrow_array
(
"SELECT schema_data, version FROM bz_schema"
);
my
$bz_schema
;
unless
(
$bz_schema
=
Bugzilla
->
memcached
->
get
({
key
=>
'bz_schema'
}))
{
$bz_schema
=
$self
->
selectrow_arrayref
(
"SELECT schema_data, version FROM bz_schema"
);
Bugzilla
->
memcached
->
set
({
key
=>
'bz_schema'
,
value
=>
$bz_schema
});
}
(
die
"_bz_real_schema tried to read the bz_schema table but it's empty!"
)
if
!
$
dat
a
;
if
!
$
bz_schem
a
;
$self
->
{
private_real_schema
}
=
$self
->
_bz_schema
->
deserialize_abstract
(
$
data
,
$version
);
$self
->
{
private_real_schema
}
=
$self
->
_bz_schema
->
deserialize_abstract
(
$
bz_schema
->
[
0
],
$bz_schema
->
[
1
]
);
return
$self
->
{
private_real_schema
};
}
...
...
@@ -1411,6 +1416,8 @@ sub _bz_store_real_schema {
$sth
->
bind_param
(
1
,
$store_me
,
$self
->
BLOB_TYPE
);
$sth
->
bind_param
(
2
,
$schema_version
);
$sth
->
execute
();
Bugzilla
->
memcached
->
clear
({
key
=>
'bz_schema'
});
}
# For bz_populate_enum_tables
...
...
Bugzilla/Install/Requirements.pm
View file @
a11f4823
...
...
@@ -394,6 +394,14 @@ sub OPTIONAL_MODULES {
version
=>
'0'
,
feature
=>
[
'typesniffer'
],
},
# memcached
{
package
=>
'Cache-Memcached'
,
module
=>
'Cache::Memcached'
,
version
=>
'0'
,
feature
=>
[
'memcached'
],
},
);
my
$extra_modules
=
_get_extension_requirements
(
'OPTIONAL_MODULES'
);
...
...
@@ -417,6 +425,7 @@ use constant FEATURE_FILES => (
'Bugzilla/JobQueue/*'
,
'jobqueue.pl'
],
patch_viewer
=>
[
'Bugzilla/Attachment/PatchReader.pm'
],
updates
=>
[
'Bugzilla/Update.pm'
],
memcached
=>
[
'Bugzilla/Memcache.pm'
],
);
# This implements the REQUIRED_MODULES and OPTIONAL_MODULES stuff
...
...
Bugzilla/Memcached.pm
0 → 100644
View file @
a11f4823
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package
Bugzilla::
Memcached
;
use
5.10.1
;
use
strict
;
use
warnings
;
use
Bugzilla::
Error
;
use
Bugzilla::
Util
qw(trick_taint)
;
use
Scalar::
Util
qw(blessed)
;
sub
_new
{
my
$invocant
=
shift
;
my
$class
=
ref
(
$invocant
)
||
$invocant
;
my
$self
=
{};
# always return an object to simplify calling code when memcached is
# disabled.
if
(
Bugzilla
->
feature
(
'memcached'
)
&&
Bugzilla
->
params
->
{
memcached_servers
})
{
require
Cache::
Memcached
;
$self
->
{
memcached
}
=
Cache::
Memcached
->
new
({
servers
=>
[
split
(
/[, ]+/
,
Bugzilla
->
params
->
{
memcached_servers
})
],
namespace
=>
Bugzilla
->
params
->
{
memcached_namespace
}
||
''
,
});
}
return
bless
(
$self
,
$class
);
}
sub
set
{
my
(
$self
,
$args
)
=
@_
;
return
unless
$self
->
{
memcached
};
# { key => $key, value => $value }
if
(
exists
$args
->
{
key
})
{
$self
->
_set
(
$args
->
{
key
},
$args
->
{
value
});
}
# { table => $table, id => $id, name => $name, data => $data }
elsif
(
exists
$args
->
{
table
}
&&
exists
$args
->
{
id
}
&&
exists
$args
->
{
name
})
{
# For caching of Bugzilla::Object, we have to be able to clear the
# cached values when given either the object's id or name.
my
(
$table
,
$id
,
$name
,
$data
)
=
@$args
{
qw(table id name data)
};
$self
->
_set
(
"$table.id.$id"
,
$data
);
if
(
defined
$name
)
{
$self
->
_set
(
"$table.name_id.$name"
,
$id
);
$self
->
_set
(
"$table.id_name.$id"
,
$name
);
}
}
else
{
ThrowCodeError
(
'params_required'
,
{
function
=>
"Bugzilla::Memcached::set"
,
params
=>
[
'key'
,
'table'
]
});
}
}
sub
get
{
my
(
$self
,
$args
)
=
@_
;
return
unless
$self
->
{
memcached
};
# { key => $key }
if
(
exists
$args
->
{
key
})
{
return
$self
->
_get
(
$args
->
{
key
});
}
# { table => $table, id => $id }
elsif
(
exists
$args
->
{
table
}
&&
exists
$args
->
{
id
})
{
my
(
$table
,
$id
)
=
@$args
{
qw(table id)
};
return
$self
->
_get
(
"$table.id.$id"
);
}
# { table => $table, name => $name }
elsif
(
exists
$args
->
{
table
}
&&
exists
$args
->
{
name
})
{
my
(
$table
,
$name
)
=
@$args
{
qw(table name)
};
return
unless
my
$id
=
$self
->
_get
(
"$table.name_id.$name"
);
return
$self
->
_get
(
"$table.id.$id"
);
}
else
{
ThrowCodeError
(
'params_required'
,
{
function
=>
"Bugzilla::Memcached::get"
,
params
=>
[
'key'
,
'table'
]
});
}
}
sub
clear
{
my
(
$self
,
$args
)
=
@_
;
return
unless
$self
->
{
memcached
};
# { key => $key }
if
(
exists
$args
->
{
key
})
{
$self
->
_delete
(
$args
->
{
key
});
}
# { table => $table, id => $id }
elsif
(
exists
$args
->
{
table
}
&&
exists
$args
->
{
id
})
{
my
(
$table
,
$id
)
=
@$args
{
qw(table id)
};
my
$name
=
$self
->
_get
(
"$table.id_name.$id"
);
$self
->
_delete
(
"$table.id.$id"
);
$self
->
_delete
(
"$table.name_id.$name"
)
if
defined
$name
;
$self
->
_delete
(
"$table.id_name.$id"
);
}
# { table => $table, name => $name }
elsif
(
exists
$args
->
{
table
}
&&
exists
$args
->
{
name
})
{
my
(
$table
,
$name
)
=
@$args
{
qw(table name)
};
return
unless
my
$id
=
$self
->
_get
(
"$table.name_id.$name"
);
$self
->
_delete
(
"$table.id.$id"
);
$self
->
_delete
(
"$table.name_id.$name"
);
$self
->
_delete
(
"$table.id_name.$id"
);
}
else
{
ThrowCodeError
(
'params_required'
,
{
function
=>
"Bugzilla::Memcached::clear"
,
params
=>
[
'key'
,
'table'
]
});
}
}
sub
clear_all
{
my
(
$self
)
=
@_
;
return
unless
my
$memcached
=
$self
->
{
memcached
};
if
(
!
$memcached
->
incr
(
"prefix"
,
1
))
{
$memcached
->
add
(
"prefix"
,
time
());
}
}
# in order to clear all our keys, we add a prefix to all our keys. when we
# need to "clear" all current keys, we increment the prefix.
sub
_prefix
{
my
(
$self
)
=
@_
;
# we don't want to change prefixes in the middle of a request
my
$request_cache
=
Bugzilla
->
request_cache
;
if
(
!
$request_cache
->
{
memcached_prefix
})
{
my
$memcached
=
$self
->
{
memcached
};
my
$prefix
=
$memcached
->
get
(
"prefix"
);
if
(
!
$prefix
)
{
$prefix
=
time
();
if
(
!
$memcached
->
add
(
"prefix"
,
$prefix
))
{
# if this failed, either another process set the prefix, or
# memcached is down. assume we lost the race, and get the new
# value. if that fails, memcached is down so use a dummy
# prefix for this request.
$prefix
=
$memcached
->
get
(
"prefix"
)
||
0
;
}
}
$request_cache
->
{
memcached_prefix
}
=
$prefix
;
}
return
$request_cache
->
{
memcached_prefix
};
}
sub
_set
{
my
(
$self
,
$key
,
$value
)
=
@_
;
if
(
blessed
(
$value
))
{
# we don't support blessed objects
ThrowCodeError
(
'param_invalid'
,
{
function
=>
"Bugzilla::Memcached::set"
,
param
=>
"value"
});
}
return
$self
->
{
memcached
}
->
set
(
$self
->
_prefix
.
':'
.
$key
,
$value
);
}
sub
_get
{
my
(
$self
,
$key
)
=
@_
;
my
$value
=
$self
->
{
memcached
}
->
get
(
$self
->
_prefix
.
':'
.
$key
);
return
unless
defined
$value
;
# detaint returned values
# hashes and arrays are detainted just one level deep
if
(
ref
(
$value
)
eq
'HASH'
)
{
map
{
defined
(
$_
)
&&
trick_taint
(
$_
)
}
values
%
$value
;
}
elsif
(
ref
(
$value
)
eq
'ARRAY'
)
{
trick_taint
(
$_
)
foreach
@$value
;
}
elsif
(
!
ref
(
$value
))
{
trick_taint
(
$value
);
}
return
$value
;
}
sub
_delete
{
my
(
$self
,
$key
)
=
@_
;
return
$self
->
{
memcached
}
->
delete
(
$self
->
_prefix
.
':'
.
$key
);
}
1
;
__END__
=head1 NAME
Bugzilla::Memcached - Interface between Bugzilla and Memcached.
=head1 SYNOPSIS
use Bugzilla;
my $memcached = Bugzilla->memcached;
# grab data from the cache. there is no need to check if memcached is
# available or enabled.
my $data = $memcached->get({ key => 'data_key' });
if (!defined $data) {
# not in cache, generate the data and populate the cache for next time
$data = some_long_process();
$memcached->set({ key => 'data_key', value => $data });
}
# do something with $data
# updating the profiles table directly shouldn't be attempted unless you know
# what you're doing. if you do update a table directly, you need to clear that
# object from memcached.
$dbh->do("UPDATE profiles SET request_count=10 WHERE login_name=?", undef, $login);
$memcached->clear({ table => 'profiles', name => $login });
=head1 DESCRIPTION
If Memcached is installed and configured, Bugzilla can use it to cache data
across requests and between webheads. Unlike the request and process caches,
only scalars, hashrefs, and arrayrefs can be stored in Memcached.
Memcached integration is only required for large installations of Bugzilla --
if you have multiple webheads then configuring Memcache is recommended.
L<Bugzilla::Memcached> provides an interface to a Memcached server/servers, with
the ability to get, set, or clear entries from the cache.
The stored value must be an unblessed hashref, unblessed array ref, or a
scalar. Currently nested data structures are supported but require manual
de-tainting after reading from Memcached (flat data structures are automatically
de-tainted).
All values are stored in the Memcached systems using the prefix configured with
the C<memcached_namespace> parameter, as well as an additional prefix managed
by this class to allow all values to be cleared when C<checksetup.pl> is
executed.
Do not create an instance of this object directly, instead use
L<Bugzilla-E<gt>memcached()|Bugzilla/memcached>.
=head1 METHODS
=head2 Setting
Adds a value to Memcached.
=over
=item C<set({ key =E<gt> $key, value =E<gt> $value })>
Adds the C<value> using the specific C<key>.
=item C<set({ table =E<gt> $table, id =E<gt> $id, name =E<gt> $name, data =E<gt> $data })>
Adds the C<data> using a keys generated from the C<table>, C<id>, and C<name>.
All three parameters must be provided, however C<name> can be provided but set
to C<undef>.
This is a convenience method which allows cached data to be later retrieved by
specifying the C<table> and either the C<id> or C<name>.
=back
=head2 Getting
Retrieves a value from Memcached. Returns C<undef> if no matching values were
found in the cache.
=over
=item C<get({ key =E<gt> $key })>
Return C<value> with the specified C<key>.
=item C<get({ table =E<gt> $table, id =E<gt> $id })>
Return C<value> with the specified C<table> and C<id>.
=item C<get({ table =E<gt> $table, name =E<gt> $name })>
Return C<value> with the specified C<table> and C<name>.
=back
=head2 Clearing
Removes the matching value from Memcached.
=over
=item C<clear({ key =E<gt> $key })>
Removes C<value> with the specified C<key>.
=item C<clear({ table =E<gt> $table, id =E<gt> $id })>
Removes C<value> with the specified C<table> and C<id>, as well as the
corresponding C<table> and C<name> entry.
=item C<clear({ table =E<gt> $table, name =E<gt> $name })>
Removes C<value> with the specified C<table> and C<name>, as well as the
corresponding C<table> and C<id> entry.
=item C<clear_all>
Removes all values from the cache.
=back
=head1 Bugzilla::Object CACHE
The main driver for Memcached integration is to allow L<Bugzilla::Object> based
objects to be automatically cached in Memcache. This is enabled on a
per-package basis by setting the C<USE_MEMCACHED> constant to any true value.
The current implementation is an opt-in (USE_MEMCACHED is false by default),
however this will change to opt-out once further testing has been completed
(USE_MEMCACHED will be true by default).
=head1 DIRECT DATABASE UPDATES
If an object is cached and the database is updated directly (instead of via
C<$object-E<gt>update()>), then it's possible for the data in the cache to be
out of sync with the database.
As an example let's consider an extension which adds a timestamp field
C<last_activitiy_ts> to the profiles table and user object which contains the
user's last activity. If the extension were to call C<$user-E<gt>update()>,
then an audit entry would be created for each change to the C<last_activity_ts>
field, which is undesirable.
To remedy this, the extension updates the table directly. It's critical with
Memcached that it then clears the cache:
$dbh->do("UPDATE profiles SET last_activity_ts=? WHERE userid=?",
undef, $timestamp, $user_id);
Bugzilla->memcached->clear({ table => 'profiles', id => $user_id });
Bugzilla/Object.pm
View file @
a11f4823
...
...
@@ -34,6 +34,11 @@ use constant AUDIT_CREATES => 1;
use
constant
AUDIT_UPDATES
=>
1
;
use
constant
AUDIT_REMOVES
=>
1
;
# When USE_MEMCACHED is true, the class is suitable for serialisation to
# Memcached. This will be flipped to true by default once the majority of
# Bugzilla Object have been tested with Memcached.
use
constant
USE_MEMCACHED
=>
0
;
# This allows the JSON-RPC interface to return Bugzilla::Object instances
# as though they were hashes. In the future, this may be modified to return
# less information.
...
...
@@ -48,11 +53,41 @@ sub new {
my
$class
=
ref
(
$invocant
)
||
$invocant
;
my
$param
=
shift
;
my
$object
=
$class
->
_cache_get
(
$param
);
my
$object
=
$class
->
_
object_
cache_get
(
$param
);
return
$object
if
$object
;
$object
=
$class
->
new_from_hash
(
$class
->
_load_from_db
(
$param
));
$class
->
_cache_set
(
$param
,
$object
);
my
(
$data
,
$set_memcached
);
if
(
Bugzilla
->
feature
(
'memcached'
)
&&
$class
->
USE_MEMCACHED
&&
ref
(
$param
)
eq
'HASH'
&&
$param
->
{
cache
})
{
if
(
defined
$param
->
{
id
})
{
$data
=
Bugzilla
->
memcached
->
get
({
table
=>
$class
->
DB_TABLE
,
id
=>
$param
->
{
id
},
});
}
elsif
(
defined
$param
->
{
name
})
{
$data
=
Bugzilla
->
memcached
->
get
({
table
=>
$class
->
DB_TABLE
,
name
=>
$param
->
{
name
},
});
}
$set_memcached
=
$data
?
0
:
1
;
}
$data
||=
$class
->
_load_from_db
(
$param
);
if
(
$data
&&
$set_memcached
)
{
Bugzilla
->
memcached
->
set
({
table
=>
$class
->
DB_TABLE
,
id
=>
$data
->
{
$class
->
ID_FIELD
},
name
=>
$data
->
{
$class
->
NAME_FIELD
},
data
=>
$data
,
});
}
$object
=
$class
->
new_from_hash
(
$data
);
$class
->
_object_cache_set
(
$param
,
$object
);
return
$object
;
}
...
...
@@ -157,32 +192,32 @@ sub initialize {
}
# Provides a mechanism for objects to be cached in the request_cache
sub
_cache_get
{
sub
_
object_
cache_get
{
my
$class
=
shift
;
my
(
$param
)
=
@_
;
my
$cache_key
=
$class
->
cache_key
(
$param
)
my
$cache_key
=
$class
->
object_
cache_key
(
$param
)
||
return
;
return
Bugzilla
->
request_cache
->
{
$cache_key
};
}
sub
_cache_set
{
sub
_
object_
cache_set
{
my
$class
=
shift
;
my
(
$param
,
$object
)
=
@_
;
my
$cache_key
=
$class
->
cache_key
(
$param
)
my
$cache_key
=
$class
->
object_
cache_key
(
$param
)
||
return
;
Bugzilla
->
request_cache
->
{
$cache_key
}
=
$object
;
}
sub
_cache_remove
{
sub
_
object_
cache_remove
{
my
$class
=
shift
;
my
(
$param
)
=
@_
;
$param
->
{
cache
}
=
1
;
my
$cache_key
=
$class
->
cache_key
(
$param
)
my
$cache_key
=
$class
->
object_
cache_key
(
$param
)
||
return
;
delete
Bugzilla
->
request_cache
->
{
$cache_key
};
}
sub
cache_key
{
sub
object_
cache_key
{
my
$class
=
shift
;
my
(
$param
)
=
@_
;
if
(
ref
(
$param
)
&&
$param
->
{
cache
}
&&
(
$param
->
{
id
}
||
$param
->
{
name
}))
{
...
...
@@ -461,8 +496,9 @@ sub update {
$self
->
audit_log
(
\%
changes
)
if
$self
->
AUDIT_UPDATES
;
$dbh
->
bz_commit_transaction
();
$self
->
_cache_remove
({
id
=>
$self
->
id
});
$self
->
_cache_remove
({
name
=>
$self
->
name
})
if
$self
->
name
;
Bugzilla
->
memcached
->
clear
({
table
=>
$table
,
id
=>
$self
->
id
});
$self
->
_object_cache_remove
({
id
=>
$self
->
id
});
$self
->
_object_cache_remove
({
name
=>
$self
->
name
})
if
$self
->
name
;
if
(
wantarray
)
{
return
(
\%
changes
,
$old_self
);
...
...
@@ -481,8 +517,9 @@ sub remove_from_db {
$self
->
audit_log
(
AUDIT_REMOVE
)
if
$self
->
AUDIT_REMOVES
;
$dbh
->
do
(
"DELETE FROM $table WHERE $id_field = ?"
,
undef
,
$self
->
id
);
$dbh
->
bz_commit_transaction
();
$self
->
_cache_remove
({
id
=>
$self
->
id
});
$self
->
_cache_remove
({
name
=>
$self
->
name
})
if
$self
->
name
;
Bugzilla
->
memcached
->
clear
({
table
=>
$table
,
id
=>
$self
->
id
});
$self
->
_object_cache_remove
({
id
=>
$self
->
id
});
$self
->
_object_cache_remove
({
name
=>
$self
->
name
})
if
$self
->
name
;
undef
$self
;
}
...
...
@@ -1399,7 +1436,7 @@ C<0> otherwise.
=over
=item cache_key
=item
object_
cache_key
=item check_time
...
...
checksetup.pl
View file @
a11f4823
...
...
@@ -206,6 +206,9 @@ Bugzilla::Hook::process('install_before_final_checks', { silent => $silent });
# Final checks
###########################################################################
# Clear all keys from Memcached
Bugzilla
->
memcached
->
clear_all
();
# Check if the default parameter for urlbase is still set, and if so, give
# notification that they should go and visit editparams.cgi
if
(
Bugzilla
->
params
->
{
'urlbase'
}
eq
''
)
{
...
...
template/en/default/admin/params/memcached.html.tmpl
0 → 100644
View file @
a11f4823
[%# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
#%]
[%
title = "Memcached"
desc = "Set up Memcached integration"
%]
[% param_descs = {
memcached_servers =>
"If this option is set, $terms.Bugzilla will integrate with Memcached. " _
"Specify one of more server, separated by spaces, using hostname:port " _
"notation (for example: 127.0.0.1:11211).",
memcached_namespace =>
"Specify a string to prefix to each key on Memcached.",
}
%]
template/en/default/setup/strings.txt.pl
View file @
a11f4823
...
...
@@ -91,6 +91,7 @@ END
feature_jsonrpc_faster
=>
'Make JSON-RPC Faster'
,
feature_new_charts
=>
'New Charts'
,
feature_old_charts
=>
'Old Charts'
,
feature_memcached
=>
'Memcached Support'
,
feature_mod_perl
=>
'mod_perl'
,
feature_moving
=>
'Move Bugs Between Installations'
,
feature_patch_viewer
=>
'Patch Viewer'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment