/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.cassandra.io; import java.nio.ByteBuffer; import java.util.SortedSet; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Iterators; import com.google.common.collect.PeekingIterator; import org.apache.cassandra.db.ColumnFamily; import org.apache.cassandra.db.IColumn; import org.apache.cassandra.db.marshal.AbstractType; /** * An observer of column values for a particular column name. Implementations will receive a call * to 'observe' when a value for the given column name is located. Observers should only be shown * column values after garbage collection. */ public abstract class ColumnObserver implements Comparable<ColumnObserver> { // name of the column we'd like to observe (and the name's type) public final ByteBuffer name; public final AbstractType type; public ColumnObserver(ByteBuffer name, AbstractType type) { this.name = name; this.type = type; } public final void maybeObserve(ColumnFamily row) { IColumn col = row.getColumn(name); if (col != null && !col.isMarkedForDelete()) observe(col.value()); } abstract protected void observe(ByteBuffer value); @Override public int compareTo(ColumnObserver that) { assert this.type == that.type; if (this == that) return 0; return compareToName(that.name); } public int compareToName(ByteBuffer name) { return this.type.compare(this.name, name); } /** * Wrapper iterator that observes IColumns passed through it with a set of Observers. */ public static class Iterator extends AbstractIterator<IColumn> { private final java.util.Iterator<IColumn> src; private final PeekingIterator<ColumnObserver> observers; private Iterator(java.util.Iterator<IColumn> src, SortedSet<? extends ColumnObserver> observers) { super(); this.src = src; this.observers = Iterators.peekingIterator(observers.iterator()); } public static java.util.Iterator<IColumn> apply(java.util.Iterator<IColumn> src, SortedSet<? extends ColumnObserver> observers) { if (observers.isEmpty()) return src; return new Iterator(src, observers); } @Override protected IColumn computeNext() { if (!src.hasNext()) return endOfData(); IColumn col = src.next(); if (col.isMarkedForDelete()) return col; // see if anyone wants to observe the current column while (observers.hasNext()) { int c = observers.peek().compareToName(col.name()); if (c < 0) // haven't reached the next column to observe: continue break; else if (c == 0) { // found an observed column: pop the observer and observe observers.next().observe(col.value()); break; } else // this observer missed its chance to observe: skip it observers.next(); } return col; } } }