25
25
package org .hibernate .action ;
26
26
27
27
import org .hibernate .HibernateException ;
28
+ import org .hibernate .cache .access .SoftLock ;
29
+ import org .hibernate .cache .access .EntityRegionAccessStrategy ;
30
+ import org .hibernate .cache .access .CollectionRegionAccessStrategy ;
28
31
import org .hibernate .persister .entity .EntityPersister ;
29
32
import org .hibernate .persister .entity .Queryable ;
33
+ import org .hibernate .persister .collection .CollectionPersister ;
30
34
import org .hibernate .engine .SessionFactoryImplementor ;
31
35
import org .hibernate .engine .SessionImplementor ;
32
36
36
40
import java .util .Iterator ;
37
41
import java .util .HashSet ;
38
42
import java .util .ArrayList ;
43
+ import java .util .Arrays ;
39
44
40
45
/**
41
- * Implementation of BulkOperationCleanupAction.
46
+ * An {@link org.hibernate.engine.ActionQueue} {@link Executable} for ensuring
47
+ * shared cache cleanup in relation to performed bulk HQL queries.
48
+ * <p/>
49
+ * NOTE: currently this executes for <tt>INSERT</tt> queries as well as
50
+ * <tt>UPDATE</tt> and <tt>DELETE</tt> queries. For <tt>INSERT</tt> it is
51
+ * really not needed as we'd have no invalid entity/collection data to
52
+ * cleanup (we'd still nee to invalidate the appropriate update-timestamps
53
+ * regions) as a result of this query.
42
54
*
43
55
* @author Steve Ebersole
44
56
*/
45
57
public class BulkOperationCleanupAction implements Executable , Serializable {
46
-
47
- private final SessionImplementor session ;
48
-
49
- private final Set affectedEntityNames = new HashSet ();
50
- private final Set affectedCollectionRoles = new HashSet ();
51
- private final Serializable [] spaces ;
52
-
53
- public BulkOperationCleanupAction (SessionImplementor session , Queryable [] affectedQueryables ) {
54
- this .session = session ;
55
- // TODO : probably better to calculate these and pass them in, as it'll be more performant
58
+ private final Serializable [] affectedTableSpaces ;
59
+
60
+ private final Set entityCleanups = new HashSet ();
61
+ private final Set collectionCleanups = new HashSet ();
62
+
63
+ /**
64
+ * Constructs an action to cleanup "affected cache regions" based on the
65
+ * affected entity persisters. The affected regions are defined as the
66
+ * region (if any) of the entity persisters themselves, plus the
67
+ * collection regions for any collection in which those entity
68
+ * persisters participate as elements/keys/etc.
69
+ *
70
+ * @param session The session to which this request is tied.
71
+ * @param affectedQueryables The affected entity persisters.
72
+ */
73
+ public BulkOperationCleanupAction (
74
+ SessionImplementor session ,
75
+ Queryable [] affectedQueryables ) {
76
+ SessionFactoryImplementor factory = session .getFactory ();
56
77
ArrayList tmpSpaces = new ArrayList ();
57
78
for ( int i = 0 ; i < affectedQueryables .length ; i ++ ) {
79
+ tmpSpaces .addAll ( Arrays .asList ( affectedQueryables [i ].getQuerySpaces () ) );
58
80
if ( affectedQueryables [i ].hasCache () ) {
59
- affectedEntityNames .add ( affectedQueryables [i ].getEntityName () );
81
+ entityCleanups .add (
82
+ new EntityCleanup (
83
+ affectedQueryables [i ].getCacheAccessStrategy ()
84
+ )
85
+ );
60
86
}
61
- Set roles = session . getFactory () .getCollectionRolesByEntityParticipant ( affectedQueryables [i ].getEntityName () );
87
+ Set roles = factory .getCollectionRolesByEntityParticipant ( affectedQueryables [i ].getEntityName () );
62
88
if ( roles != null ) {
63
- affectedCollectionRoles .addAll ( roles );
64
- }
65
- for ( int y = 0 ; y < affectedQueryables [i ].getQuerySpaces ().length ; y ++ ) {
66
- tmpSpaces .add ( affectedQueryables [i ].getQuerySpaces ()[y ] );
89
+ Iterator itr = roles .iterator ();
90
+ while ( itr .hasNext () ) {
91
+ String role = ( String ) itr .next ();
92
+ CollectionPersister collectionPersister = factory .getCollectionPersister ( role );
93
+ if ( collectionPersister .hasCache () ) {
94
+ collectionCleanups .add (
95
+ new CollectionCleanup (
96
+ collectionPersister .getCacheAccessStrategy ()
97
+ )
98
+ );
99
+ }
100
+ }
67
101
}
68
102
}
69
- this .spaces = new Serializable [ tmpSpaces .size () ];
70
- for ( int i = 0 ; i < tmpSpaces .size (); i ++ ) {
71
- this .spaces [i ] = ( Serializable ) tmpSpaces .get ( i );
72
- }
103
+
104
+ this .affectedTableSpaces = ( Serializable [] ) tmpSpaces .toArray ( new Serializable [ tmpSpaces .size () ] );
73
105
}
74
-
75
- /** Create an action that will evict collection and entity regions based on queryspaces (table names).
76
- * TODO: cache the autodetected information and pass it in instead.
77
- **/
78
- public BulkOperationCleanupAction (SessionImplementor session , Set querySpaces ) {
79
- this .session = session ;
80
-
81
- Set tmpSpaces = new HashSet (querySpaces );
106
+
107
+ /**
108
+ * Constructs an action to cleanup "affected cache regions" based on a
109
+ * set of affected table spaces. This differs from {@link #BulkOperationCleanupAction(SessionImplementor, Queryable[])}
110
+ * in that here we have the affected <strong>table names</strong>. From those
111
+ * we deduce the entity persisters whcih are affected based on the defined
112
+ * {@link EntityPersister#getQuerySpaces() table spaces}; and from there, we
113
+ * determine the affected collection regions based on any collections
114
+ * in which those entity persisters participate as elements/keys/etc.
115
+ *
116
+ * @param session The session to which this request is tied.
117
+ * @param tableSpaces The table spaces.
118
+ */
119
+ public BulkOperationCleanupAction (SessionImplementor session , Set tableSpaces ) {
120
+ Set tmpSpaces = new HashSet (tableSpaces );
82
121
SessionFactoryImplementor factory = session .getFactory ();
83
122
Iterator iterator = factory .getAllClassMetadata ().entrySet ().iterator ();
84
123
while ( iterator .hasNext () ) {
@@ -87,54 +126,84 @@ public BulkOperationCleanupAction(SessionImplementor session, Set querySpaces) {
87
126
EntityPersister persister = factory .getEntityPersister ( entityName );
88
127
Serializable [] entitySpaces = persister .getQuerySpaces ();
89
128
90
- if (affectedEntity ( querySpaces , entitySpaces )) {
129
+ if ( affectedEntity ( tableSpaces , entitySpaces ) ) {
130
+ tmpSpaces .addAll ( Arrays .asList ( entitySpaces ) );
91
131
if ( persister .hasCache () ) {
92
- affectedEntityNames .add ( persister .getEntityName () );
132
+ entityCleanups .add (
133
+ new EntityCleanup (
134
+ persister .getCacheAccessStrategy ()
135
+ )
136
+ );
93
137
}
94
138
Set roles = session .getFactory ().getCollectionRolesByEntityParticipant ( persister .getEntityName () );
95
139
if ( roles != null ) {
96
- affectedCollectionRoles .addAll ( roles );
97
- }
98
- for ( int y = 0 ; y < entitySpaces .length ; y ++ ) {
99
- tmpSpaces .add ( entitySpaces [y ] );
140
+ Iterator itr = roles .iterator ();
141
+ while ( itr .hasNext () ) {
142
+ String role = ( String ) itr .next ();
143
+ CollectionPersister collectionPersister = factory .getCollectionPersister ( role );
144
+ if ( collectionPersister .hasCache () ) {
145
+ collectionCleanups .add (
146
+ new CollectionCleanup (
147
+ collectionPersister .getCacheAccessStrategy ()
148
+ )
149
+ );
150
+ }
151
+ }
100
152
}
101
153
}
102
-
103
154
}
104
- this .spaces = (Serializable []) tmpSpaces .toArray ( new Serializable [tmpSpaces .size ()] );
155
+
156
+ this .affectedTableSpaces = ( Serializable [] ) tmpSpaces .toArray ( new Serializable [ tmpSpaces .size () ] );
105
157
}
106
158
107
159
108
- /** returns true if no queryspaces or if there are a match */
109
- private boolean affectedEntity (Set querySpaces , Serializable [] entitySpaces ) {
110
- if (querySpaces ==null || querySpaces .isEmpty ()) {
160
+ /**
161
+ * Check to determine whether the table spaces reported by an entity
162
+ * persister match against the defined affected table spaces.
163
+ *
164
+ * @param affectedTableSpaces The table spaces reported to be affected by
165
+ * the query.
166
+ * @param checkTableSpaces The table spaces (from the entity persister)
167
+ * to check against the affected table spaces.
168
+ *
169
+ * @return True if there are affected table spaces and any of the incoming
170
+ * check table spaces occur in that set.
171
+ */
172
+ private boolean affectedEntity (
173
+ Set affectedTableSpaces ,
174
+ Serializable [] checkTableSpaces ) {
175
+ if ( affectedTableSpaces == null || affectedTableSpaces .isEmpty () ) {
111
176
return true ;
112
177
}
113
-
114
- for ( int i = 0 ; i < entitySpaces .length ; i ++ ) {
115
- if ( querySpaces .contains ( entitySpaces [i ] ) ) {
178
+
179
+ for ( int i = 0 ; i < checkTableSpaces .length ; i ++ ) {
180
+ if ( affectedTableSpaces .contains ( checkTableSpaces [i ] ) ) {
116
181
return true ;
117
182
}
118
183
}
119
184
return false ;
120
185
}
121
186
122
- public void init () {
123
- evictEntityRegions ();
124
- evictCollectionRegions ();
187
+ public Serializable [] getPropertySpaces () {
188
+ return affectedTableSpaces ;
125
189
}
126
190
127
191
public boolean hasAfterTransactionCompletion () {
128
192
return true ;
129
193
}
130
194
131
195
public void afterTransactionCompletion (boolean success ) throws HibernateException {
132
- evictEntityRegions ();
133
- evictCollectionRegions ();
134
- }
196
+ Iterator itr = entityCleanups .iterator ();
197
+ while ( itr .hasNext () ) {
198
+ final EntityCleanup cleanup = ( EntityCleanup ) itr .next ();
199
+ cleanup .release ();
200
+ }
135
201
136
- public Serializable [] getPropertySpaces () {
137
- return spaces ;
202
+ itr = collectionCleanups .iterator ();
203
+ while ( itr .hasNext () ) {
204
+ final CollectionCleanup cleanup = ( CollectionCleanup ) itr .next ();
205
+ cleanup .release ();
206
+ }
138
207
}
139
208
140
209
public void beforeExecutions () throws HibernateException {
@@ -145,23 +214,33 @@ public void execute() throws HibernateException {
145
214
// nothing to do
146
215
}
147
216
148
- private void evictEntityRegions () {
149
- if ( affectedEntityNames != null ) {
150
- Iterator itr = affectedEntityNames .iterator ();
151
- while ( itr .hasNext () ) {
152
- final String entityName = ( String ) itr .next ();
153
- session .getFactory ().evictEntity ( entityName );
154
- }
217
+ private static class EntityCleanup {
218
+ private final EntityRegionAccessStrategy cacheAccess ;
219
+ private final SoftLock cacheLock ;
220
+
221
+ private EntityCleanup (EntityRegionAccessStrategy cacheAccess ) {
222
+ this .cacheAccess = cacheAccess ;
223
+ this .cacheLock = cacheAccess .lockRegion ();
224
+ cacheAccess .removeAll ();
225
+ }
226
+
227
+ private void release () {
228
+ cacheAccess .unlockRegion ( cacheLock );
155
229
}
156
230
}
157
231
158
- private void evictCollectionRegions () {
159
- if ( affectedCollectionRoles != null ) {
160
- Iterator itr = affectedCollectionRoles .iterator ();
161
- while ( itr .hasNext () ) {
162
- final String roleName = ( String ) itr .next ();
163
- session .getFactory ().evictCollection ( roleName );
164
- }
232
+ private static class CollectionCleanup {
233
+ private final CollectionRegionAccessStrategy cacheAccess ;
234
+ private final SoftLock cacheLock ;
235
+
236
+ private CollectionCleanup (CollectionRegionAccessStrategy cacheAccess ) {
237
+ this .cacheAccess = cacheAccess ;
238
+ this .cacheLock = cacheAccess .lockRegion ();
239
+ cacheAccess .removeAll ();
240
+ }
241
+
242
+ private void release () {
243
+ cacheAccess .unlockRegion ( cacheLock );
165
244
}
166
245
}
167
246
}
0 commit comments