All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.notedb.rebuild.EventSorter Maven / Gradle / Ivy

There is a newer version: 3.10.0-rc4
Show newest version
// Copyright (C) 2016 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.notedb.rebuild;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.SetMultimap;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.PriorityQueue;

/**
 * Helper to sort a list of events.
 *
 * 

Events are sorted in two passes: * *

    *
  1. Sort by natural order (timestamp, patch set, author, etc.) *
  2. Postpone any events with dependencies to occur only after all of their dependencies, where * this violates natural order. *
* * {@link #sort()} modifies the event list in place (similar to {@link Collections#sort(List)}), but * does not modify any event. In particular, events might end up out of order with respect to * timestamp; callers are responsible for adjusting timestamps later if they prefer monotonicity. */ class EventSorter { private final List out; private final LinkedHashSet sorted; private ListMultimap waiting; private SetMultimap deps; EventSorter(List events) { LinkedHashSet all = new LinkedHashSet<>(events); out = events; for (Event e : events) { for (Event d : e.deps) { checkArgument(all.contains(d), "dep %s of %s not in input list", d, e); } } all.clear(); sorted = all; // Presized. } void sort() { // First pass: sort by natural order. PriorityQueue todo = new PriorityQueue<>(out); // Populate waiting map after initial sort to preserve natural order. waiting = MultimapBuilder.hashKeys().arrayListValues().build(); deps = MultimapBuilder.hashKeys().hashSetValues().build(); for (Event e : todo) { for (Event d : e.deps) { deps.put(e, d); waiting.put(d, e); } } // Second pass: enforce dependencies. int size = out.size(); while (!todo.isEmpty()) { process(todo.remove(), todo); } checkState( sorted.size() == size, "event sort expected %s elements, got %s", size, sorted.size()); // Modify out in-place a la Collections#sort. out.clear(); out.addAll(sorted); } void process(Event e, PriorityQueue todo) { if (sorted.contains(e)) { return; // Already emitted. } if (!deps.get(e).isEmpty()) { // Not all events that e depends on have been emitted yet. Ignore e for // now; it will get added back to the queue in the block below once its // last dependency is processed. return; } // All events that e depends on have been emitted, so e can be emitted. sorted.add(e); // Remove e from the dependency set of all events waiting on e, and add // those events back to the queue in the original priority order for // reconsideration. for (Event w : waiting.get(e)) { deps.get(w).remove(e); todo.add(w); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy