Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
Openfire
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Openfire
Commits
8a003ae9
Commit
8a003ae9
authored
Oct 22, 2015
by
Tom Evans
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #311 from tevans/OF-921
OF-921: Reset MUC group cache for group changes
parents
a9f16fc0
14dab0df
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
153 additions
and
70 deletions
+153
-70
ConcurrentGroupList.java
.../org/jivesoftware/openfire/group/ConcurrentGroupList.java
+49
-24
ConcurrentGroupMap.java
...a/org/jivesoftware/openfire/group/ConcurrentGroupMap.java
+103
-45
GroupAwareMap.java
src/java/org/jivesoftware/openfire/group/GroupAwareMap.java
+1
-1
No files found.
src/java/org/jivesoftware/openfire/group/ConcurrentGroupList.java
View file @
8a003ae9
...
@@ -16,13 +16,14 @@ import org.xmpp.packet.JID;
...
@@ -16,13 +16,14 @@ import org.xmpp.packet.JID;
*/
*/
public
class
ConcurrentGroupList
<
T
>
extends
CopyOnWriteArrayList
<
T
>
implements
GroupAwareList
<
T
>
{
public
class
ConcurrentGroupList
<
T
>
extends
CopyOnWriteArrayList
<
T
>
implements
GroupAwareList
<
T
>
{
private
static
final
long
serialVersionUID
=
-
8884698048047935327
L
;
private
static
final
long
serialVersionUID
=
7735849143650412115
L
;
// This set is used to optimize group operations within this list.
// This set is used to optimize group operations within this list.
// We only populate this set when it's needed to dereference the
// We only populate this set when it's needed to dereference the
// groups in the base list, but once it exists we keep it in sync
// groups in the base list, but once it exists we keep it in sync
// via the various add/remove operations.
// via the various add/remove operations.
private
transient
Set
<
Group
>
groupsInList
;
// NOTE: added volatile keyword for double-check idiom (lazy instantiation)
private
volatile
transient
Set
<
String
>
knownGroupNamesInList
;
public
ConcurrentGroupList
()
{
public
ConcurrentGroupList
()
{
super
();
super
();
...
@@ -61,20 +62,41 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -61,20 +62,41 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
* @return A Set containing the groups in the list
* @return A Set containing the groups in the list
*/
*/
@Override
@Override
public
synchronized
Set
<
Group
>
getGroups
()
{
public
Set
<
Group
>
getGroups
()
{
if
(
groupsInList
==
null
)
{
Set
<
Group
>
result
=
new
HashSet
<
Group
>();
groupsInList
=
new
HashSet
<
Group
>();
for
(
String
groupName
:
getKnownGroupNamesInList
())
{
// add all the groups into the group set
result
.
add
(
Group
.
resolveFrom
(
groupName
));
Iterator
<
T
>
iterator
=
iterator
();
}
while
(
iterator
.
hasNext
())
{
return
result
;
T
listItem
=
iterator
.
next
();
}
Group
group
=
Group
.
resolveFrom
(
listItem
);
if
(
group
!=
null
)
{
/**
groupsInList
.
add
(
group
);
* Accessor uses the "double-check idiom" (j2se 5.0+) for proper lazy instantiation.
};
* Additionally, the set is not cached until there is at least one group in the list.
*
* @return the known group names among the items in the list
*/
private
Set
<
String
>
getKnownGroupNamesInList
()
{
Set
<
String
>
result
=
knownGroupNamesInList
;
if
(
result
==
null
)
{
synchronized
(
this
)
{
result
=
knownGroupNamesInList
;
if
(
result
==
null
)
{
result
=
new
HashSet
<
String
>();
// add all the groups into the group set
Iterator
<
T
>
iterator
=
iterator
();
while
(
iterator
.
hasNext
())
{
T
listItem
=
iterator
.
next
();
Group
group
=
Group
.
resolveFrom
(
listItem
);
if
(
group
!=
null
)
{
result
.
add
(
group
.
getName
());
};
}
knownGroupNamesInList
=
result
.
isEmpty
()
?
null
:
result
;
}
}
}
}
}
return
groupsInLis
t
;
return
resul
t
;
}
}
/**
/**
...
@@ -88,14 +110,17 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -88,14 +110,17 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
private
synchronized
boolean
syncGroups
(
Object
item
,
boolean
addOrRemove
)
{
private
synchronized
boolean
syncGroups
(
Object
item
,
boolean
addOrRemove
)
{
boolean
result
=
false
;
boolean
result
=
false
;
// only sync if the group list has been instantiated
// only sync if the group list has been instantiated
if
(
group
sInList
!=
null
)
{
if
(
knownGroupName
sInList
!=
null
)
{
Group
group
=
Group
.
resolveFrom
(
item
);
Group
group
=
Group
.
resolveFrom
(
item
);
if
(
group
!=
null
)
{
if
(
group
!=
null
)
{
result
=
true
;
result
=
true
;
if
(
addOrRemove
==
ADD
)
{
if
(
addOrRemove
==
ADD
)
{
groupsInList
.
add
(
group
);
knownGroupNamesInList
.
add
(
group
.
getName
()
);
}
else
if
(
addOrRemove
==
REMOVE
)
{
}
else
if
(
addOrRemove
==
REMOVE
)
{
groupsInList
.
remove
(
group
);
knownGroupNamesInList
.
remove
(
group
.
getName
());
if
(
knownGroupNamesInList
.
isEmpty
())
{
knownGroupNamesInList
=
null
;
}
}
}
}
}
}
}
...
@@ -155,7 +180,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -155,7 +180,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
if
(
changed
)
{
if
(
changed
)
{
// drop the transient set, will be rebuilt when/if needed
// drop the transient set, will be rebuilt when/if needed
synchronized
(
this
)
{
synchronized
(
this
)
{
group
sInList
=
null
;
knownGroupName
sInList
=
null
;
}
}
}
}
return
changed
;
return
changed
;
...
@@ -167,7 +192,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -167,7 +192,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
if
(
changed
)
{
if
(
changed
)
{
// drop the transient set, will be rebuilt when/if needed
// drop the transient set, will be rebuilt when/if needed
synchronized
(
this
)
{
synchronized
(
this
)
{
group
sInList
=
null
;
knownGroupName
sInList
=
null
;
}
}
}
}
return
changed
;
return
changed
;
...
@@ -179,7 +204,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -179,7 +204,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
if
(
added
>
0
)
{
if
(
added
>
0
)
{
// drop the transient set, will be rebuilt when/if needed
// drop the transient set, will be rebuilt when/if needed
synchronized
(
this
)
{
synchronized
(
this
)
{
group
sInList
=
null
;
knownGroupName
sInList
=
null
;
}
}
}
}
return
added
;
return
added
;
...
@@ -189,7 +214,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -189,7 +214,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
public
void
clear
()
{
public
void
clear
()
{
super
.
clear
();
super
.
clear
();
synchronized
(
this
)
{
synchronized
(
this
)
{
group
sInList
=
null
;
knownGroupName
sInList
=
null
;
}
}
}
}
...
@@ -199,7 +224,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -199,7 +224,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
if
(
changed
)
{
if
(
changed
)
{
// drop the transient set, will be rebuilt when/if needed
// drop the transient set, will be rebuilt when/if needed
synchronized
(
this
)
{
synchronized
(
this
)
{
group
sInList
=
null
;
knownGroupName
sInList
=
null
;
}
}
}
}
return
changed
;
return
changed
;
...
@@ -211,7 +236,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
...
@@ -211,7 +236,7 @@ public class ConcurrentGroupList<T> extends CopyOnWriteArrayList<T> implements G
if
(
changed
)
{
if
(
changed
)
{
// drop the transient set, will be rebuilt when/if needed
// drop the transient set, will be rebuilt when/if needed
synchronized
(
this
)
{
synchronized
(
this
)
{
group
sInList
=
null
;
knownGroupName
sInList
=
null
;
}
}
}
}
return
changed
;
return
changed
;
...
...
src/java/org/jivesoftware/openfire/group/ConcurrentGroupMap.java
View file @
8a003ae9
...
@@ -17,20 +17,20 @@ import org.xmpp.packet.JID;
...
@@ -17,20 +17,20 @@ import org.xmpp.packet.JID;
public
class
ConcurrentGroupMap
<
K
,
V
>
extends
ConcurrentHashMap
<
K
,
V
>
implements
GroupAwareMap
<
K
,
V
>
{
public
class
ConcurrentGroupMap
<
K
,
V
>
extends
ConcurrentHashMap
<
K
,
V
>
implements
GroupAwareMap
<
K
,
V
>
{
private
static
final
long
serialVersionUID
=
-
2068242013524715293
L
;
private
static
final
long
serialVersionUID
=
5479781418678223200
L
;
// These sets are used to optimize group operations within this map.
// These sets are used to optimize group operations within this map.
// We only populate these sets when they are needed to dereference the
// We only populate these sets when they are needed to dereference the
// groups in the base map, but once they exist we keep them in sync
// groups in the base map, but once they exist we keep them in sync
// via the various put/remove operations.
// via the various put/remove operations.
private
transient
Set
<
Group
>
groupsFromKeys
;
// NOTE: added volatile keyword for double-check idiom (lazy instantiation)
private
transient
Set
<
Group
>
groupsFromValue
s
;
private
volatile
transient
Set
<
String
>
knownGroupNamesFromKey
s
;
private
volatile
transient
Set
<
String
>
knownGroupNamesFromValues
;
/**
/**
* Returns true if the key list contains the given JID. If the JID
* Returns true if the key list contains the given JID. If the JID
is not found in the
*
is not found in the key list, search the key list for groups and
*
key list (exact match), search the key list for groups and look for the JID in
*
look for the JID in each of the corresponding groups
.
*
each of the corresponding groups (implied match)
.
*
*
* @param key The target, presumably a JID
* @param key The target, presumably a JID
* @return True if the target is in the key list, or in any groups in the key list
* @return True if the target is in the key list, or in any groups in the key list
...
@@ -52,9 +52,9 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -52,9 +52,9 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
/**
/**
* Returns true if the map has an entry value matching the given JID. If the JID
* Returns true if the map has an entry value matching the given JID. If the JID
is not
*
is not found explicitly, search the values for groups and search
*
found in the value set (exact match), search the value set for groups and look for the
*
for the JID in each of the corresponding groups
.
*
JID in each of the corresponding groups (implied match)
.
*
*
* @param value The target, presumably a JID
* @param value The target, presumably a JID
* @return True if the target is in the value set, or in any groups in the value set
* @return True if the target is in the value set, or in any groups in the value set
...
@@ -64,7 +64,7 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -64,7 +64,7 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
if
(
containsValue
(
value
))
{
if
(
containsValue
(
value
))
{
found
=
true
;
found
=
true
;
}
else
if
(
value
instanceof
JID
)
{
}
else
if
(
value
instanceof
JID
)
{
// look for group JIDs in the list of
key
s and dereference as needed
// look for group JIDs in the list of
value
s and dereference as needed
JID
target
=
(
JID
)
value
;
JID
target
=
(
JID
)
value
;
Iterator
<
Group
>
iterator
=
getGroupsFromValues
().
iterator
();
Iterator
<
Group
>
iterator
=
getGroupsFromValues
().
iterator
();
while
(!
found
&&
iterator
.
hasNext
())
{
while
(!
found
&&
iterator
.
hasNext
())
{
...
@@ -81,19 +81,11 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -81,19 +81,11 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
*/
*/
@Override
@Override
public
synchronized
Set
<
Group
>
getGroupsFromKeys
()
{
public
synchronized
Set
<
Group
>
getGroupsFromKeys
()
{
if
(
groupsFromKeys
==
null
)
{
Set
<
Group
>
result
=
new
HashSet
<
Group
>();
groupsFromKeys
=
new
HashSet
<
Group
>();
for
(
String
groupName
:
getKnownGroupNamesFromKeys
())
{
// add all the groups into the group set
result
.
add
(
Group
.
resolveFrom
(
groupName
));
Iterator
<
K
>
iterator
=
keySet
().
iterator
();
while
(
iterator
.
hasNext
())
{
K
key
=
iterator
.
next
();
Group
group
=
Group
.
resolveFrom
(
key
);
if
(
group
!=
null
)
{
groupsFromKeys
.
add
(
group
);
};
}
}
}
return
groupsFromKeys
;
return
result
;
}
}
/**
/**
...
@@ -103,19 +95,71 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -103,19 +95,71 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
*/
*/
@Override
@Override
public
synchronized
Set
<
Group
>
getGroupsFromValues
()
{
public
synchronized
Set
<
Group
>
getGroupsFromValues
()
{
if
(
groupsFromValues
==
null
)
{
Set
<
Group
>
result
=
new
HashSet
<
Group
>();
groupsFromValues
=
new
HashSet
<
Group
>();
for
(
String
groupName
:
getKnownGroupNamesFromValues
())
{
// add all the groups into the group set
result
.
add
(
Group
.
resolveFrom
(
groupName
));
Iterator
<
V
>
iterator
=
values
().
iterator
();
}
while
(
iterator
.
hasNext
())
{
return
result
;
V
value
=
iterator
.
next
();
}
Group
group
=
Group
.
resolveFrom
(
value
);
if
(
group
!=
null
)
{
groupsFromValues
.
add
(
group
);
/**
};
* Accessor uses the "double-check idiom" (j2se 5.0+) for proper lazy instantiation.
* Additionally, nothing is cached until there is at least one group in the map's keys.
*
* @return the known group names among the items in the list
*/
private
Set
<
String
>
getKnownGroupNamesFromKeys
()
{
Set
<
String
>
result
=
knownGroupNamesFromKeys
;
if
(
result
==
null
)
{
synchronized
(
this
)
{
result
=
knownGroupNamesFromKeys
;
if
(
result
==
null
)
{
result
=
new
HashSet
<
String
>();
// add all the groups into the group set
Iterator
<
K
>
iterator
=
keySet
().
iterator
();
while
(
iterator
.
hasNext
())
{
K
key
=
iterator
.
next
();
Group
group
=
Group
.
resolveFrom
(
key
);
if
(
group
!=
null
)
{
result
.
add
(
group
.
getName
());
};
}
knownGroupNamesFromKeys
=
result
.
isEmpty
()
?
null
:
result
;
}
}
}
}
}
return
groupsFromValues
;
return
result
;
}
/**
* Accessor uses the "double-check idiom" (j2se 5.0+) for proper lazy instantiation.
* Additionally, nothing is cached until there is at least one group in the map's value set.
*
* @return the known group names among the items in the list
*/
private
Set
<
String
>
getKnownGroupNamesFromValues
()
{
Set
<
String
>
result
=
knownGroupNamesFromValues
;
if
(
result
==
null
)
{
synchronized
(
this
)
{
result
=
knownGroupNamesFromValues
;
if
(
result
==
null
)
{
result
=
new
HashSet
<
String
>();
// add all the groups into the group set
Iterator
<
V
>
iterator
=
values
().
iterator
();
while
(
iterator
.
hasNext
())
{
V
key
=
iterator
.
next
();
Group
group
=
Group
.
resolveFrom
(
key
);
if
(
group
!=
null
)
{
result
.
add
(
group
.
getName
());
};
}
knownGroupNamesFromValues
=
result
.
isEmpty
()
?
null
:
result
;
}
}
}
return
result
;
}
}
/**
/**
...
@@ -129,16 +173,23 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -129,16 +173,23 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
*/
*/
private
synchronized
boolean
syncGroups
(
Object
item
,
boolean
keyOrValue
,
boolean
addOrRemove
)
{
private
synchronized
boolean
syncGroups
(
Object
item
,
boolean
keyOrValue
,
boolean
addOrRemove
)
{
boolean
result
=
false
;
boolean
result
=
false
;
Set
<
Group
>
groupSet
=
(
keyOrValue
==
KEYS
)
?
groupsFromKeys
:
group
sFromValues
;
Set
<
String
>
groupSet
=
(
keyOrValue
==
KEYS
)
?
knownGroupNamesFromKeys
:
knownGroupName
sFromValues
;
// only sync if the group list has been instantiated
// only sync if the group list has been instantiated
if
(
groupSet
!=
null
)
{
if
(
groupSet
!=
null
)
{
Group
group
=
Group
.
resolveFrom
(
item
);
Group
group
=
Group
.
resolveFrom
(
item
);
if
(
group
!=
null
)
{
if
(
group
!=
null
)
{
result
=
true
;
result
=
true
;
if
(
addOrRemove
==
ADD
)
{
if
(
addOrRemove
==
ADD
)
{
groupSet
.
add
(
group
);
groupSet
.
add
(
group
.
getName
()
);
}
else
if
(
addOrRemove
==
REMOVE
)
{
}
else
if
(
addOrRemove
==
REMOVE
)
{
groupSet
.
remove
(
group
);
groupSet
.
remove
(
group
.
getName
());
if
(
groupSet
.
isEmpty
())
{
if
(
keyOrValue
==
KEYS
)
{
knownGroupNamesFromKeys
=
null
;
}
else
{
knownGroupNamesFromValues
=
null
;
}
}
}
}
}
}
}
}
...
@@ -180,10 +231,7 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -180,10 +231,7 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
public
void
putAll
(
Map
<?
extends
K
,
?
extends
V
>
m
)
{
public
void
putAll
(
Map
<?
extends
K
,
?
extends
V
>
m
)
{
super
.
putAll
(
m
);
super
.
putAll
(
m
);
// drop the transient sets; will be rebuilt when/if needed
// drop the transient sets; will be rebuilt when/if needed
synchronized
(
this
)
{
clearCache
();
groupsFromKeys
=
null
;
groupsFromValues
=
null
;
}
}
}
...
@@ -234,14 +282,24 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
...
@@ -234,14 +282,24 @@ public class ConcurrentGroupMap<K, V> extends ConcurrentHashMap<K, V> implement
@Override
@Override
public
void
clear
()
{
public
void
clear
()
{
super
.
clear
();
super
.
clear
();
synchronized
(
this
)
{
clearCache
();
groupsFromKeys
=
null
;
}
groupsFromValues
=
null
;
}
/**
* Certain operations imply that our locally cached group list(s) should
* be dropped and recreated. For example, when an ad-hoc client command
* is used to add a member to a group, the underlying group instance is
* actually dropped from the global Group cache, with the effect that our
* cache would be referring to an orphaned Group instance.
*/
private
synchronized
void
clearCache
()
{
knownGroupNamesFromKeys
=
null
;
knownGroupNamesFromValues
=
null
;
}
}
private
static
final
boolean
KEYS
=
true
;
private
static
final
boolean
KEYS
=
true
;
private
static
final
boolean
VALUES
=
false
;
private
static
final
boolean
VALUES
=
false
;
private
static
final
boolean
ADD
=
true
;
private
static
final
boolean
ADD
=
true
;
private
static
final
boolean
REMOVE
=
false
;
private
static
final
boolean
REMOVE
=
false
;
}
}
src/java/org/jivesoftware/openfire/group/GroupAwareMap.java
View file @
8a003ae9
...
@@ -23,7 +23,7 @@ public interface GroupAwareMap<K, V> extends Map<K, V> {
...
@@ -23,7 +23,7 @@ public interface GroupAwareMap<K, V> extends Map<K, V> {
public
boolean
includesKey
(
Object
key
);
public
boolean
includesKey
(
Object
key
);
/**
/**
* Returns true if the map
has a key
referencing the given JID. If the JID
* Returns true if the map
contains a value
referencing the given JID. If the JID
* is not found explicitly, search the values for groups and look
* is not found explicitly, search the values for groups and look
* for the JID in each of the corresponding groups.
* for the JID in each of the corresponding groups.
*
*
...
...
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