change_broker_lazy_update.patch
src/com/goldencode/p2j/persist/AdaptiveQuery.java 2023-03-09 12:31:10 +0000 | ||
---|---|---|
349 | 349 |
** set is created, ProgressiveResults can no longer be the type returned. |
350 | 350 |
** RAA 20230221 If the query will be executed lazy, then it is no longer registered as a |
351 | 351 |
** listener. |
352 |
** RAA 20230302 Added a condition that checks if the buffer is active before seeing if the query |
|
353 |
** supports lazy mode. This is part of the registration as a listener process. |
|
352 | 354 |
*/ |
353 | 355 | |
354 | 356 |
/* |
... | ... | |
531 | 533 |
/** Determines if this will be unregistered from ChangeBroker on cleanup. */ |
532 | 534 |
private boolean unregisterOnCleanup = false; |
533 | 535 |
|
536 |
/** Flag to check the ability to fetch the records in a lazy manner, without server-side invalidation */ |
|
537 |
private Boolean lazyMode = null; |
|
538 |
|
|
534 | 539 |
/** |
535 | 540 |
* Default constructor. Initialization is deferred until <code>initialize()</code> is |
536 | 541 |
* called. |
... | ... | |
559 | 564 |
|
560 | 565 |
adapter = new ResultsAdapter(new ResultsSource()); |
561 | 566 |
|
562 |
ChangeBroker.get().addListener(this);
|
|
567 |
registerRecordChangeListeners(null);
|
|
563 | 568 |
|
564 | 569 |
TransactionManager.registerOffEndQuery(this); |
565 | 570 |
|
... | ... | |
592 | 597 |
|
593 | 598 |
adapter = new ResultsAdapter(new ResultsSource()); |
594 | 599 |
|
595 |
ChangeBroker.get().addListener(this);
|
|
600 |
registerRecordChangeListeners(null);
|
|
596 | 601 |
|
597 | 602 |
TransactionManager.registerOffEndQuery(this); |
598 | 603 |
|
... | ... | |
665 | 670 |
addWhereExpression(whereExpr); |
666 | 671 |
} |
667 | 672 |
|
668 |
ChangeBroker.get().addListener(this); |
|
669 |
// buffer persistence may not be active yet - what do we do? what about scrolling? |
|
670 |
// if (buffer == null || !buffer.getPersistence().supportsLazyQueryResultsMode()) |
|
671 |
// { |
|
672 |
// ChangeBroker.get().addListener(this); |
|
673 |
// } |
|
673 |
registerRecordChangeListeners(null); |
|
674 | 674 |
|
675 | 675 |
return this; |
676 | 676 |
} |
... | ... | |
1110 | 1110 |
{ |
1111 | 1111 |
closed = false; |
1112 | 1112 |
|
1113 |
int scope = BufferManager.get().findNearestExternal(); |
|
1114 |
RecordBuffer[] buffers = getRecordBuffers(); |
|
1115 |
|
|
1116 |
for (RecordBuffer buffer : buffers) |
|
1117 |
{ |
|
1118 |
scope = ((scope == -1) |
|
1119 |
? buffer.getScopeOpenDepth() |
|
1120 |
: Math.min(scope, buffer.getScopeOpenDepth())); |
|
1121 |
} |
|
1122 |
|
|
1123 |
if (scope != -1) |
|
1124 |
{ |
|
1125 |
registerRecordChangeListeners(scope); |
|
1113 |
// rule out the scope computation and registering if this is a lazy query anyway |
|
1114 |
// lazy queries don't require server-side invalidation as it supports it at the database level |
|
1115 |
if (shouldRegisterRecordChangeListeners()) |
|
1116 |
{ |
|
1117 |
int scope = BufferManager.get().findNearestExternal(); |
|
1118 |
RecordBuffer[] buffers = getRecordBuffers(); |
|
1119 |
|
|
1120 |
for (RecordBuffer buffer : buffers) |
|
1121 |
{ |
|
1122 |
scope = ((scope == -1) |
|
1123 |
? buffer.getScopeOpenDepth() |
|
1124 |
: Math.min(scope, buffer.getScopeOpenDepth())); |
|
1125 |
} |
|
1126 |
|
|
1127 |
if (scope != -1) |
|
1128 |
{ |
|
1129 |
registerRecordChangeListeners(Integer.valueOf(scope)); |
|
1130 |
} |
|
1126 | 1131 |
} |
1127 | 1132 | |
1128 | 1133 |
if (cursor != null) |
... | ... | |
1137 | 1142 |
} |
1138 | 1143 |
|
1139 | 1144 |
/** |
1145 |
* Check if this type of query should register record change listeners. Use this |
|
1146 |
* to avoid computing any scope for registration and end up with a no registration |
|
1147 |
* behavior. |
|
1148 |
* |
|
1149 |
* @return {@code true} if we should invest time into computing the scope in order |
|
1150 |
* to call {@link #registerRecordChangeListeners} or {@code false} if we |
|
1151 |
* can skip doing any work to honor {@link #registerRecordChangeListeners}. |
|
1152 |
*/ |
|
1153 |
@Override |
|
1154 |
public boolean shouldRegisterRecordChangeListeners() |
|
1155 |
{ |
|
1156 |
return !isLazyMode(); |
|
1157 |
} |
|
1158 |
|
|
1159 |
/** |
|
1140 | 1160 |
* Register all <code>RecordChangeListener</code>s associated with this |
1141 | 1161 |
* query (if any), with the context-local <code>ChangeBroker</code> at the |
1142 | 1162 |
* indicated scope. |
1143 | 1163 |
* |
1144 | 1164 |
* @param scope |
1145 | 1165 |
* Scope at which listeners should be registered with the change |
1146 |
* broker. |
|
1166 |
* broker. {@code null} means register at the closest scope.
|
|
1147 | 1167 |
*/ |
1148 |
public void registerRecordChangeListeners(int scope) |
|
1168 |
@Override |
|
1169 |
public void registerRecordChangeListeners(Integer scope) |
|
1149 | 1170 |
{ |
1171 |
// Queries over temporary tables have their invalidation dealt with by the |
|
1172 |
// lazy mechanism, so there is no need to register them as listeners. |
|
1173 |
if (isLazyMode()) |
|
1174 |
{ |
|
1175 |
return; |
|
1176 |
} |
|
1177 |
|
|
1178 |
if (scope == null) |
|
1179 |
{ |
|
1180 |
ChangeBroker.get().addListener(this); |
|
1181 |
return; |
|
1182 |
} |
|
1183 |
|
|
1150 | 1184 |
ChangeBroker.get().addListener(this, scope); |
1151 | 1185 |
|
1152 | 1186 |
// if these were added as global listeners in ChangeBroker remember to remove them |
... | ... | |
2237 | 2271 |
throws PersistenceException |
2238 | 2272 |
{ |
2239 | 2273 |
ArrayList<QueryComponent> components = components(); |
2240 |
// rather check persistence if supports this |
|
2241 |
if (components.size() == 1 && components.get(0).getBuffer().isTemporary() && !isScrolling()) |
|
2242 |
{ |
|
2243 |
return; |
|
2244 |
} |
|
2274 | ||
2245 | 2275 |
boolean preselect = isPreselect(); |
2246 | 2276 |
boolean invalidate = true; |
2247 | 2277 |
boolean cacheAll = false; |
... | ... | |
3005 | 3035 |
throws PersistenceException |
3006 | 3036 |
{ |
3007 | 3037 |
Results results = null; |
3008 |
boolean lazyMode = persistence.supportsLazyQueryResultsMode(); |
|
3009 |
if (lazyMode && !isScrolling()) |
|
3038 |
if (isLazyMode()) |
|
3010 | 3039 |
{ |
3011 | 3040 |
Long templateRowid = getTemplateQueryRowid(args); |
3012 | 3041 |
if (templateRowid != null) |
... | ... | |
3015 | 3044 |
return results; |
3016 | 3045 |
} |
3017 | 3046 |
|
3018 |
return new ScrollingResults(persistence, executeScroll(persistence, fql, args, lazyMode));
|
|
3047 |
return new ScrollingResults(persistence, executeScroll(persistence, fql, args, true));
|
|
3019 | 3048 |
} |
3020 | 3049 |
|
3021 | 3050 |
if (cacheOnReval || probablyRequiresResort()) |
... | ... | |
3457 | 3486 |
} |
3458 | 3487 |
|
3459 | 3488 |
/** |
3489 |
* Helper method to understand if this query is going to use lazy query results mode. |
|
3490 |
* Such mode automatically solves invalidation at the database side, so there is no |
|
3491 |
* need to invalidate in the server-side. |
|
3492 |
* |
|
3493 |
* @return {@code true} if this is a lazy mode query with implicit invalidation handling |
|
3494 |
*/ |
|
3495 |
private boolean isLazyMode() |
|
3496 |
{ |
|
3497 |
if (lazyMode == null) |
|
3498 |
{ |
|
3499 |
ArrayList<QueryComponent> components = components(); |
|
3500 |
if (components == null || components.size() != 1) |
|
3501 |
{ |
|
3502 |
return false; |
|
3503 |
} |
|
3504 |
RecordBuffer buffer = components.get(0).getBuffer(); |
|
3505 |
lazyMode = buffer != null && |
|
3506 |
buffer.isActive() && |
|
3507 |
buffer.getPersistence().supportsLazyQueryResultsMode(); |
|
3508 |
} |
|
3509 |
|
|
3510 |
return lazyMode; |
|
3511 |
} |
|
3512 |
|
|
3513 |
/** |
|
3460 | 3514 |
* Indicate whether the query results as initially fetched are likely to require a re-sort before they |
3461 | 3515 |
* are returned. This decision is based on whether the sort phrase exists and does not match any legacy |
3462 | 3516 |
* index of the first query component table. |
src/com/goldencode/p2j/persist/CompoundQuery.java 2023-03-09 12:35:59 +0000 | ||
---|---|---|
239 | 239 |
** SVL 20230113 More performance improvements by replacing some "for-each" loops with indexed |
240 | 240 |
** "for" loops. |
241 | 241 |
** 082 CA 20230221 Javadoc fixes. |
242 |
** 083 AL2 20230309 Optimized record change listener registration to avoid computing scope for queries |
|
243 |
* which dont require registration. |
|
242 | 244 |
*/ |
243 | 245 | |
244 | 246 |
/* |
... | ... | |
2445 | 2447 |
{ |
2446 | 2448 |
CompoundComponent comp = compoundComponents.get(i); |
2447 | 2449 |
Joinable query = comp.getQuery(); |
2450 |
if (!query.shouldRegisterRecordChangeListeners()) |
|
2451 |
{ |
|
2452 |
continue; |
|
2453 |
} |
|
2454 |
|
|
2448 | 2455 |
int scope = externalScope; |
2449 | 2456 |
RecordBuffer[] buffers = query.getRecordBuffers(); |
2450 | 2457 |
|
... | ... | |
2458 | 2465 |
|
2459 | 2466 |
if (scope != -1) |
2460 | 2467 |
{ |
2461 |
query.registerRecordChangeListeners(scope);
|
|
2468 |
query.registerRecordChangeListeners(Integer.valueOf(scope));
|
|
2462 | 2469 |
} |
2463 | 2470 |
} |
2464 | 2471 |
|
src/com/goldencode/p2j/persist/Joinable.java 2023-03-09 12:13:48 +0000 | ||
---|---|---|
48 | 48 |
** are not the same), to be aware of the external buffers (i.e. added for CAN-FIND |
49 | 49 |
** sub-select clauses). The translate will be performed before the query is being |
50 | 50 |
** executed. |
51 |
** 020 AL2 20230309 Allow registering change listeners at latest scope using null. |
|
51 | 52 |
*/ |
52 | 53 | |
53 | 54 |
/* |
... | ... | |
251 | 252 |
public Object[] peekLast(); |
252 | 253 |
|
253 | 254 |
/** |
255 |
* Check if this type of query should register record change listeners. Use this |
|
256 |
* to avoid computing any scope for registration and end up with a no registration |
|
257 |
* behavior. |
|
258 |
* |
|
259 |
* @return {@code true} if we should invest time into computing the scope in order |
|
260 |
* to call {@link #registerRecordChangeListeners} or {@code false} if we |
|
261 |
* can skip doing any work to honor {@link #registerRecordChangeListeners}. |
|
262 |
*/ |
|
263 |
public default boolean shouldRegisterRecordChangeListeners() |
|
264 |
{ |
|
265 |
return true; |
|
266 |
} |
|
267 |
|
|
268 |
/** |
|
254 | 269 |
* Register all <code>RecordChangeListener</code>s associated with this |
255 | 270 |
* query (if any), with the context-local <code>ChangeBroker</code> at the |
256 | 271 |
* indicated scope. |
257 | 272 |
* |
258 | 273 |
* @param scope |
259 | 274 |
* Scope at which listeners should be registered with the change |
260 |
* broker. |
|
275 |
* broker. {@code null} means register at the closest scope.
|
|
261 | 276 |
*/ |
262 |
public void registerRecordChangeListeners(int scope);
|
|
277 |
public void registerRecordChangeListeners(Integer scope);
|
|
263 | 278 |
|
264 | 279 |
/** |
265 | 280 |
* Create an adaptive query component based on the information in this query (which is |
src/com/goldencode/p2j/persist/PreselectQuery.java 2023-03-09 12:27:04 +0000 | ||
---|---|---|
2211 | 2211 |
return super.getExternalBuffers(); |
2212 | 2212 |
} |
2213 | 2213 |
|
2214 | ||
2215 |
/** |
|
2216 |
* Check if this type of query should register record change listeners. Use this |
|
2217 |
* to avoid computing any scope for registration and end up with a no registration |
|
2218 |
* behavior. |
|
2219 |
* |
|
2220 |
* @return {@code true} if we should invest time into computing the scope in order |
|
2221 |
* to call {@link #registerRecordChangeListeners} or {@code false} if we |
|
2222 |
* can skip doing any work to honor {@link #registerRecordChangeListeners}. |
|
2223 |
*/ |
|
2224 |
@Override |
|
2225 |
public boolean shouldRegisterRecordChangeListeners() |
|
2226 |
{ |
|
2227 |
return false; |
|
2228 |
} |
|
2229 |
|
|
2214 | 2230 |
/** |
2215 | 2231 |
* Register all <code>RecordChangeListener</code>s associated with this |
2216 | 2232 |
* query (if any), with the context-local <code>ChangeBroker</code> at the |
... | ... | |
2220 | 2236 |
* |
2221 | 2237 |
* @param scope |
2222 | 2238 |
* Scope at which listeners should be registered with the change |
2223 |
* broker. |
|
2239 |
* broker. {@code null} means register at the closest scope.
|
|
2224 | 2240 |
*/ |
2225 |
public void registerRecordChangeListeners(int scope) |
|
2241 |
@Override |
|
2242 |
public void registerRecordChangeListeners(Integer scope) |
|
2226 | 2243 |
{ |
2227 | 2244 |
} |
2228 | 2245 |
|
src/com/goldencode/p2j/persist/RandomAccessQuery.java 2023-03-09 11:47:41 +0000 | ||
---|---|---|
352 | 352 |
** 116 AL2 20230210 Allow direct access for recid/unique index look-ups. |
353 | 353 |
** 20230227 Added locking if query is find-by-row-id and record is found in cache. |
354 | 354 |
** 20230307 Honor record nursery before direct access. |
355 |
** 20230309 Allow register of record change listeners at latest scope using null. |
|
355 | 356 |
*/ |
356 | 357 | |
357 | 358 |
/* |
... | ... | |
2922 | 2923 |
* |
2923 | 2924 |
* @param scope |
2924 | 2925 |
* Scope at which listeners should be registered with the change broker. |
2926 |
* {@code null} means register at the closest scope. |
|
2925 | 2927 |
*/ |
2926 |
public void registerRecordChangeListeners(int scope) |
|
2928 |
@Override |
|
2929 |
public void registerRecordChangeListeners(Integer scope) |
|
2927 | 2930 |
{ |
2928 | 2931 |
ChangeBroker broker = ChangeBroker.get(); |
2929 |
broker.addListener(this, scope); |
|
2932 |
if (scope == null) |
|
2933 |
{ |
|
2934 |
broker.addListener(this); |
|
2935 |
} |
|
2936 |
else |
|
2937 |
{ |
|
2938 |
broker.addListener(this, scope); |
|
2939 |
} |
|
2940 |
|
|
2930 | 2941 |
if (placeholderCleaner != null) |
2931 | 2942 |
{ |
2932 |
broker.addListener(placeholderCleaner, scope); |
|
2943 |
if (scope == null) |
|
2944 |
{ |
|
2945 |
broker.addListener(placeholderCleaner); |
|
2946 |
} |
|
2947 |
else |
|
2948 |
{ |
|
2949 |
broker.addListener(this, scope); |
|
2950 |
} |
|
2933 | 2951 |
} |
2934 | 2952 |
|
2935 | 2953 |
// if these were added as global listeners in ChangeBroker remember to remove them |
2936 | 2954 |
// when the query is destroyed. Otherwise, the ChangeBroker will drop them automatically |
2937 | 2955 |
// when the respective scope is finished. |
2938 |
if (scope == 0) |
|
2956 |
if (scope != null && scope == 0)
|
|
2939 | 2957 |
{ |
2940 | 2958 |
unregisterOnCleanup = true; |
2941 | 2959 |
} |