| /* |
| * 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.db; |
| |
| import java.io.DataInput; |
| import java.io.IOException; |
| |
| import org.apache.cassandra.db.composites.CellName; |
| import org.apache.cassandra.db.composites.CellNameType; |
| import org.apache.cassandra.db.composites.Composite; |
| import org.apache.cassandra.io.sstable.format.Version; |
| |
| /** |
| * Helper class to deserialize OnDiskAtom efficiently. |
| * |
| * More precisely, this class is used by the low-level readers |
| * (IndexedSliceReader and SSTableNamesIterator) to ensure we don't |
| * do more work than necessary (i.e. we don't allocate/deserialize |
| * objects for things we don't care about). |
| */ |
| public class AtomDeserializer |
| { |
| private final CellNameType type; |
| private final CellNameType.Deserializer nameDeserializer; |
| private final DataInput in; |
| private final ColumnSerializer.Flag flag; |
| private final int expireBefore; |
| private final Version version; |
| |
| // The "flag" for the next name (which correspond to the "masks" in ColumnSerializer) if it has been |
| // read already, Integer.MIN_VALUE otherwise; |
| private int nextFlags = Integer.MIN_VALUE; |
| |
| public AtomDeserializer(CellNameType type, DataInput in, ColumnSerializer.Flag flag, int expireBefore, Version version) |
| { |
| this.type = type; |
| this.nameDeserializer = type.newDeserializer(in); |
| this.in = in; |
| this.flag = flag; |
| this.expireBefore = expireBefore; |
| this.version = version; |
| } |
| |
| /** |
| * Whether or not there is more atom to read. |
| */ |
| public boolean hasNext() throws IOException |
| { |
| return nameDeserializer.hasNext(); |
| } |
| |
| /** |
| * Whether or not some atom has been read but not processed (neither readNext() nor |
| * skipNext() has been called for that atom) yet. |
| */ |
| public boolean hasUnprocessed() throws IOException |
| { |
| return nameDeserializer.hasUnprocessed(); |
| } |
| |
| /** |
| * Compare the provided composite to the next atom to read on disk. |
| * |
| * This will not read/deserialize the whole atom but only what is necessary for the |
| * comparison. Whenever we know what to do with this atom (read it or skip it), |
| * readNext or skipNext should be called. |
| */ |
| public int compareNextTo(Composite composite) throws IOException |
| { |
| return nameDeserializer.compareNextTo(composite); |
| } |
| |
| /** |
| * Returns whether the next atom is a range tombstone or not. |
| * |
| * Please note that this should only be called after compareNextTo() has been called. |
| */ |
| public boolean nextIsRangeTombstone() throws IOException |
| { |
| nextFlags = in.readUnsignedByte(); |
| return (nextFlags & ColumnSerializer.RANGE_TOMBSTONE_MASK) != 0; |
| } |
| |
| /** |
| * Returns the next atom. |
| */ |
| public OnDiskAtom readNext() throws IOException |
| { |
| Composite name = nameDeserializer.readNext(); |
| assert !name.isEmpty(); // This would imply hasNext() hasn't been called |
| |
| nextFlags = nextFlags == Integer.MIN_VALUE ? in.readUnsignedByte() : nextFlags; |
| OnDiskAtom atom = (nextFlags & ColumnSerializer.RANGE_TOMBSTONE_MASK) != 0 |
| ? type.rangeTombstoneSerializer().deserializeBody(in, name, version) |
| : type.columnSerializer().deserializeColumnBody(in, (CellName)name, nextFlags, flag, expireBefore); |
| nextFlags = Integer.MIN_VALUE; |
| return atom; |
| } |
| |
| /** |
| * Skips the next atom. |
| */ |
| public void skipNext() throws IOException |
| { |
| nameDeserializer.skipNext(); |
| nextFlags = nextFlags == Integer.MIN_VALUE ? in.readUnsignedByte() : nextFlags; |
| if ((nextFlags & ColumnSerializer.RANGE_TOMBSTONE_MASK) != 0) |
| type.rangeTombstoneSerializer().skipBody(in, version); |
| else |
| type.columnSerializer().skipColumnBody(in, nextFlags); |
| nextFlags = Integer.MIN_VALUE; |
| } |
| } |