use of com.evolveum.midpoint.prism.query.builder.S_MatchingRuleEntry in project midpoint by Evolveum.
the class SqaleAuditService method iterativeSearchCondition.
/**
* Similar to {@link SqaleRepositoryService#lastOidCondition}.
*
* TODO, lots of possible improvements:
*
* * Just like in repo iterative search this is added to the original filter with `AND`.
* However, if `timestamp` is used in the original filter, it could be replaced by stricter
* `timestamp` condition based on the `lastProcessedObject` - this is not implemented yet.
* ** TODO: If provided, do we want to add another timestamp condition?
* Would it help with partitions?
* Probably, with ID condition + ordering, it's not a big deal to leave it out.
*
* * Support for multiple order specifications from the client is not supported.
* Perhaps some short-term stateful filter/order object would be better to construct this,
* especially if it could be used in both repo and audit (with strict order attribute
* provided in constructor for example).
*
* [NOTE]
* ====
* Both `timestamp` and `repoId` is used for iterative search condition, but *only `repoId`*
* is used for additional ordering to assure strict reliable ordering.
* This can be further complicated by the fact that both `repoId` and `timestamp`
* can be part of custom ordering from client (this is different from repository, where `oid`
* is not valid for filter and ordering on the model level, even when it's usable for repository).
* If used on the top-level `AND` group, they can be be replaced by next iteration condition,
* which is likely more selective.
*
* As for the ordering, if multiple ordering is used (*not supported yet*) if `repoId` is used,
* anything after it can be omitted as irrelevant.
* ====
*
* TODO: Currently, single path ordering is supported. Finish multi-path too.
* TODO: What about nullable columns?
*/
@Nullable
private ObjectFilter iterativeSearchCondition(@Nullable AuditEventRecordType lastProcessedObject, List<? extends ObjectOrdering> providedOrdering) {
if (lastProcessedObject == null) {
return null;
}
// TODO inspect originalFilter to detect timestamp/repoId conditions.
// Only top level AND filter should be checked, anything else is irrelevant
// for the decision whether to skip additional timestamp condition.
// BTW: We CANNOT skip repoId condition, that one is CRITICAL for proper iterating.
Long lastProcessedId = lastProcessedObject.getRepoId();
XMLGregorianCalendar lastProcessedTimestamp = lastProcessedObject.getTimestamp();
if (providedOrdering == null || providedOrdering.isEmpty()) {
return prismContext().queryFor(AuditEventRecordType.class).item(AuditEventRecordType.F_REPO_ID).gt(lastProcessedId).and().item(AuditEventRecordType.F_TIMESTAMP).ge(lastProcessedTimestamp).buildFilter();
}
if (providedOrdering.size() == 1) {
ObjectOrdering objectOrdering = providedOrdering.get(0);
ItemPath orderByPath = objectOrdering.getOrderBy();
boolean asc = objectOrdering.getDirection() == OrderDirection.ASCENDING;
S_ConditionEntry filter = prismContext().queryFor(AuditEventRecordType.class).item(orderByPath);
@SuppressWarnings("unchecked") Item<PrismValue, ItemDefinition<?>> item = lastProcessedObject.asPrismContainerValue().findItem(orderByPath);
if (item.size() > 1) {
throw new IllegalArgumentException("Multi-value property for ordering is forbidden - item: " + item);
} else if (item.isEmpty()) {
// TODO what if it's nullable? is it null-first or last?
// See: https://www.postgresql.org/docs/13/queries-order.html
// "By default, null values sort as if larger than any non-null value; that is,
// NULLS FIRST is the default for DESC order, and NULLS LAST otherwise."
} else {
S_MatchingRuleEntry matchingRuleEntry = asc ? filter.gt(item.getRealValue()) : filter.lt(item.getRealValue());
filter = matchingRuleEntry.or().block().item(orderByPath).eq(item.getRealValue()).and().item(AuditEventRecordType.F_REPO_ID);
return (asc ? filter.gt(lastProcessedId) : filter.lt(lastProcessedId)).endBlock().buildFilter();
}
}
throw new IllegalArgumentException("Shouldn't get here with check in executeSearchObjectsIterative()");
}
use of com.evolveum.midpoint.prism.query.builder.S_MatchingRuleEntry in project midpoint by Evolveum.
the class NodeFoundDeadHelper method markTasksAsNotRunning.
/**
* We know that the specified nodes went from `UP` to the `DOWN` state. So we want to mark the relevant
* tasks as not running on these nodes.
*/
void markTasksAsNotRunning(Set<String> nodes, OperationResult result) throws SchemaException {
Iterator<String> iterator = nodes.iterator();
if (!iterator.hasNext()) {
return;
}
// TODO create a utility method to create multi-valued "eq" disjunction
S_MatchingRuleEntry q = PrismContext.get().queryFor(TaskType.class).item(TaskType.F_NODE).eq(iterator.next());
while (iterator.hasNext()) {
q = q.or().item(TaskType.F_NODE).eq(iterator.next());
}
ObjectQuery query = q.build();
List<PrismObject<TaskType>> tasksOnDeadNodes = repositoryService.searchObjects(TaskType.class, query, null, result);
LOGGER.info("Going to mark tasks as not running:\n{}\n{}", DebugUtil.debugDumpLazily(query, 1), DebugUtil.debugDumpLazily(tasksOnDeadNodes, 1));
for (PrismObject<TaskType> task : tasksOnDeadNodes) {
try {
markTaskAsNotRunning(task, nodes, result);
} catch (Exception e) {
LoggingUtils.logException(LOGGER, "Task couldn't be marked as not running: {}", e, task);
// We continue to mark the other tasks as not running
}
}
}
use of com.evolveum.midpoint.prism.query.builder.S_MatchingRuleEntry in project midpoint by Evolveum.
the class SqlAuditServiceImpl method iterativeSearchCondition.
/**
* See {@code SqaleRepositoryService.iterativeSearchCondition()} for more info.
* This is unsupported version only for Ninja usage.
*/
@Nullable
private ObjectFilter iterativeSearchCondition(@Nullable AuditEventRecordType lastProcessedObject, List<? extends ObjectOrdering> providedOrdering) {
if (lastProcessedObject == null) {
return null;
}
Long lastProcessedId = lastProcessedObject.getRepoId();
XMLGregorianCalendar lastProcessedTimestamp = lastProcessedObject.getTimestamp();
if (providedOrdering == null || providedOrdering.isEmpty()) {
return schemaService.prismContext().queryFor(AuditEventRecordType.class).item(AuditEventRecordType.F_REPO_ID).gt(lastProcessedId).and().item(AuditEventRecordType.F_TIMESTAMP).ge(lastProcessedTimestamp).buildFilter();
}
if (providedOrdering.size() == 1) {
ObjectOrdering objectOrdering = providedOrdering.get(0);
ItemPath orderByPath = objectOrdering.getOrderBy();
boolean asc = objectOrdering.getDirection() == OrderDirection.ASCENDING;
S_ConditionEntry filter = schemaService.prismContext().queryFor(AuditEventRecordType.class).item(orderByPath);
@SuppressWarnings("unchecked") Item<PrismValue, ItemDefinition<?>> item = lastProcessedObject.asPrismContainerValue().findItem(orderByPath);
if (item.size() > 1) {
throw new IllegalArgumentException("Multi-value property for ordering is forbidden - item: " + item);
} else if (item.isEmpty()) {
// TODO what if it's nullable? is it null-first or last?
// See: https://www.postgresql.org/docs/13/queries-order.html
// "By default, null values sort as if larger than any non-null value; that is,
// NULLS FIRST is the default for DESC order, and NULLS LAST otherwise."
} else {
S_MatchingRuleEntry matchingRuleEntry = asc ? filter.gt(item.getRealValue()) : filter.lt(item.getRealValue());
filter = matchingRuleEntry.or().block().item(orderByPath).eq(item.getRealValue()).and().item(AuditEventRecordType.F_REPO_ID);
return (asc ? filter.gt(lastProcessedId) : filter.lt(lastProcessedId)).endBlock().buildFilter();
}
}
throw new IllegalArgumentException("Shouldn't get here with check in executeSearchObjectsIterative()");
}
use of com.evolveum.midpoint.prism.query.builder.S_MatchingRuleEntry in project midpoint by Evolveum.
the class SqaleRepositoryService method lastOidCondition.
/**
* Without requested ordering, this is easy: `WHERE oid > lastOid`
*
* But with outside ordering we need to respect it and for ordering by X, Y, Z use
* (`original conditions AND` is taken care of outside of this method):
*
* ----
* ... WHERE original conditions AND (
* X > last.X
* OR (X = last.X AND Y > last.Y)
* OR (X = last.X AND Y = last.Y AND Z > last.Z)
* OR (X = last.X AND Y = last.Y ...if all equal AND OID > last.OID)
* ----
*
* This is suddenly much more fun, isn't it?
* Of course the condition `>` or `<` depends on `ASC` vs `DESC`.
*
* TODO: Currently, single path ordering is supported. Finish multi-path too.
* TODO: What about nullable columns?
*/
@Nullable
private <T extends ObjectType> ObjectFilter lastOidCondition(PrismObject<T> lastProcessedObject, List<? extends ObjectOrdering> providedOrdering) {
if (lastProcessedObject == null) {
return null;
}
String lastProcessedOid = lastProcessedObject.getOid();
if (providedOrdering == null || providedOrdering.isEmpty()) {
return prismContext().queryFor(lastProcessedObject.getCompileTimeClass()).item(OID_PATH).gt(lastProcessedOid).buildFilter();
}
if (providedOrdering.size() == 1) {
ObjectOrdering objectOrdering = providedOrdering.get(0);
ItemPath orderByPath = objectOrdering.getOrderBy();
boolean asc = objectOrdering.getDirection() == OrderDirection.ASCENDING;
S_ConditionEntry filter = prismContext().queryFor(lastProcessedObject.getCompileTimeClass()).item(orderByPath);
// noinspection rawtypes
Item<PrismValue, ItemDefinition<Item>> item = lastProcessedObject.findItem(orderByPath);
if (item.size() > 1) {
throw new IllegalArgumentException("Multi-value property for ordering is forbidden - item: " + item);
} else if (item.isEmpty()) {
// TODO what if it's nullable? is it null-first or last?
// See: https://www.postgresql.org/docs/13/queries-order.html
// "By default, null values sort as if larger than any non-null value; that is,
// NULLS FIRST is the default for DESC order, and NULLS LAST otherwise."
} else {
S_MatchingRuleEntry matchingRuleEntry = asc ? filter.gt(item.getRealValue()) : filter.lt(item.getRealValue());
filter = matchingRuleEntry.or().block().item(orderByPath).eq(item.getRealValue()).and().item(OID_PATH);
return (asc ? filter.gt(lastProcessedOid) : filter.lt(lastProcessedOid)).endBlock().buildFilter();
}
}
throw new IllegalArgumentException("Shouldn't get here with check in executeSearchObjectsIterative()");
/*
TODO: Unfinished - this is painful with fluent API. Should I call
prismContext().queryFor(lastProcessedObject.getCompileTimeClass()) for each component
and then use ObjectQueryUtil.filterAnd/Or?
// we need to handle the complicated case with externally provided ordering
S_FilterEntryOrEmpty orBlock = prismContext()
.queryFor(lastProcessedObject.getCompileTimeClass()).block();
orLoop:
for (ObjectOrdering orMasterOrdering : providedOrdering) {
Iterator<? extends ObjectOrdering> iterator = providedOrdering.iterator();
while (iterator.hasNext()) {
S_FilterEntryOrEmpty andBlock = orBlock.block();
ObjectOrdering ordering = iterator.next();
if (ordering.equals(orMasterOrdering)) {
// ...
continue orLoop;
}
orBlock = andBlock.endBlock();
}
}
return orBlock.endBlock().buildFilter();
*/
}
Aggregations