| /* |
| * 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.util; |
| |
| import java.io.*; |
| |
| import com.google.common.util.concurrent.RateLimiter; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.cassandra.db.TypeSizes; |
| import org.apache.cassandra.io.sstable.format.Version; |
| import org.apache.cassandra.utils.JVMStabilityInspector; |
| |
| public class MmappedSegmentedFile extends SegmentedFile |
| { |
| private static final Logger logger = LoggerFactory.getLogger(MmappedSegmentedFile.class); |
| |
| private final MmappedRegions regions; |
| |
| public MmappedSegmentedFile(ChannelProxy channel, int bufferSize, long length, MmappedRegions regions) |
| { |
| super(new Cleanup(channel, regions), channel, bufferSize, length); |
| this.regions = regions; |
| } |
| |
| private MmappedSegmentedFile(MmappedSegmentedFile copy) |
| { |
| super(copy); |
| this.regions = copy.regions; |
| } |
| |
| public MmappedSegmentedFile sharedCopy() |
| { |
| return new MmappedSegmentedFile(this); |
| } |
| |
| public RandomAccessReader createReader() |
| { |
| return new RandomAccessReader.Builder(channel) |
| .overrideLength(length) |
| .regions(regions) |
| .build(); |
| } |
| |
| public RandomAccessReader createReader(RateLimiter limiter) |
| { |
| return new RandomAccessReader.Builder(channel) |
| .overrideLength(length) |
| .bufferSize(bufferSize) |
| .regions(regions) |
| .limiter(limiter) |
| .build(); |
| } |
| |
| private static final class Cleanup extends SegmentedFile.Cleanup |
| { |
| private final MmappedRegions regions; |
| |
| Cleanup(ChannelProxy channel, MmappedRegions regions) |
| { |
| super(channel); |
| this.regions = regions; |
| } |
| |
| public void tidy() |
| { |
| Throwable err = regions.close(null); |
| if (err != null) |
| { |
| JVMStabilityInspector.inspectThrowable(err); |
| |
| // This is not supposed to happen |
| logger.error("Error while closing mmapped regions", err); |
| } |
| |
| super.tidy(); |
| } |
| } |
| |
| /** |
| * Overrides the default behaviour to create segments of a maximum size. |
| */ |
| static class Builder extends SegmentedFile.Builder |
| { |
| private MmappedRegions regions; |
| |
| Builder() |
| { |
| super(); |
| } |
| |
| public SegmentedFile complete(ChannelProxy channel, int bufferSize, long overrideLength) |
| { |
| long length = overrideLength > 0 ? overrideLength : channel.size(); |
| updateRegions(channel, length); |
| |
| return new MmappedSegmentedFile(channel, bufferSize, length, regions.sharedCopy()); |
| } |
| |
| private void updateRegions(ChannelProxy channel, long length) |
| { |
| if (regions != null && !regions.isValid(channel)) |
| { |
| Throwable err = regions.close(null); |
| if (err != null) |
| logger.error("Failed to close mapped regions", err); |
| |
| regions = null; |
| } |
| |
| if (regions == null) |
| regions = MmappedRegions.map(channel, length); |
| else |
| regions.extend(length); |
| } |
| |
| @Override |
| public void serializeBounds(DataOutput out, Version version) throws IOException |
| { |
| if (!version.hasBoundaries()) |
| return; |
| |
| super.serializeBounds(out, version); |
| out.writeInt(0); |
| } |
| |
| @Override |
| public void deserializeBounds(DataInput in, Version version) throws IOException |
| { |
| if (!version.hasBoundaries()) |
| return; |
| |
| super.deserializeBounds(in, version); |
| in.skipBytes(in.readInt() * TypeSizes.sizeof(0L)); |
| } |
| |
| @Override |
| public Throwable close(Throwable accumulate) |
| { |
| return super.close(regions == null |
| ? accumulate |
| : regions.close(accumulate)); |
| } |
| } |
| } |