diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java new file mode 100644 index 0000000000..e74b390db8 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java @@ -0,0 +1,149 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.query.change; + +import com.google.gerrit.server.query.AndPredicate; +import com.google.gerrit.server.query.Predicate; +import com.google.gwtorm.client.OrmException; +import com.google.gwtorm.client.ResultSet; +import com.google.gwtorm.client.impl.ListResultSet; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +class AndSource extends AndPredicate<ChangeData> implements ChangeDataSource { + private static final Comparator<Predicate<ChangeData>> CMP = + new Comparator<Predicate<ChangeData>>() { + @Override + public int compare(Predicate<ChangeData> a, Predicate<ChangeData> b) { + int ai = a instanceof ChangeDataSource ? 0 : 1; + int bi = b instanceof ChangeDataSource ? 0 : 1; + int cmp = ai - bi; + + if (cmp == 0 // + && a instanceof ChangeDataSource // + && b instanceof ChangeDataSource) { + ai = ((ChangeDataSource) a).hasChange() ? 0 : 1; + bi = ((ChangeDataSource) b).hasChange() ? 0 : 1; + cmp = ai - bi; + } + + if (cmp == 0) { + cmp = a.getCost() - b.getCost(); + } + + if (cmp == 0 // + && a instanceof ChangeDataSource // + && b instanceof ChangeDataSource) { + ChangeDataSource as = (ChangeDataSource) a; + ChangeDataSource bs = (ChangeDataSource) b; + cmp = as.getCardinality() - bs.getCardinality(); + } + + return cmp; + } + }; + + private static List<Predicate<ChangeData>> sort( + Collection<? extends Predicate<ChangeData>> that) { + ArrayList<Predicate<ChangeData>> r = + new ArrayList<Predicate<ChangeData>>(that); + Collections.sort(r, CMP); + return r; + } + + private int cardinality = -1; + + AndSource(final Collection<? extends Predicate<ChangeData>> that) { + super(sort(that)); + } + + @Override + public boolean hasChange() { + ChangeDataSource source = source(); + return source != null && source.hasChange(); + } + + @Override + public ResultSet<ChangeData> read() throws OrmException { + ChangeDataSource source = source(); + if (source == null) { + throw new OrmException("No ChangeDataSource: " + this); + } + + // TODO(spearce) This probably should be more lazy. + // + ArrayList<ChangeData> r = new ArrayList<ChangeData>(); + ChangeData last = null; + boolean skipped = false; + for (ChangeData data : source.read()) { + if (match(data)) { + r.add(data); + } else { + skipped = true; + } + last = data; + } + + if (skipped && last != null && source instanceof Paginated) { + // If we our source is a paginated source and we skipped at + // least one of its results, we may not have filled the full + // limit the caller wants. Restart the source and continue. + // + Paginated p = (Paginated) source; + while (skipped && r.size() < p.limit()) { + ChangeData lastBeforeRestart = last; + skipped = false; + last = null; + for (ChangeData data : p.restart(lastBeforeRestart)) { + if (match(data)) { + r.add(data); + } else { + skipped = true; + } + last = data; + } + } + } + + return new ListResultSet<ChangeData>(r); + } + + private ChangeDataSource source() { + for (Predicate<ChangeData> p : getChildren()) { + if (p instanceof ChangeDataSource) { + return (ChangeDataSource) p; + } + } + return null; + } + + @Override + public int getCardinality() { + if (cardinality < 0) { + cardinality = Integer.MAX_VALUE; + for (Predicate<ChangeData> p : getChildren()) { + if (p instanceof ChangeDataSource) { + int c = ((ChangeDataSource) p).getCardinality(); + cardinality = Math.min(cardinality, c); + } + } + } + return cardinality; + } +} |