| /* |
| * 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.compaction; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Set; |
| import java.util.function.Predicate; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.collect.ImmutableSet; |
| |
| import org.apache.cassandra.db.ColumnFamilyStore; |
| import org.apache.cassandra.io.sstable.format.SSTableReader; |
| import org.apache.cassandra.io.util.File; |
| import org.apache.cassandra.schema.TableMetadata; |
| import org.apache.cassandra.utils.TimeUUID; |
| |
| public final class CompactionInfo |
| { |
| public static final String ID = "id"; |
| public static final String KEYSPACE = "keyspace"; |
| public static final String COLUMNFAMILY = "columnfamily"; |
| public static final String COMPLETED = "completed"; |
| public static final String TOTAL = "total"; |
| public static final String TASK_TYPE = "taskType"; |
| public static final String UNIT = "unit"; |
| public static final String COMPACTION_ID = "compactionId"; |
| public static final String SSTABLES = "sstables"; |
| public static final String TARGET_DIRECTORY = "targetDirectory"; |
| |
| private final TableMetadata metadata; |
| private final OperationType tasktype; |
| private final long completed; |
| private final long total; |
| private final Unit unit; |
| private final TimeUUID compactionId; |
| private final ImmutableSet<SSTableReader> sstables; |
| private final String targetDirectory; |
| |
| public CompactionInfo(TableMetadata metadata, OperationType tasktype, long completed, long total, Unit unit, TimeUUID compactionId, Collection<? extends SSTableReader> sstables, String targetDirectory) |
| { |
| this.tasktype = tasktype; |
| this.completed = completed; |
| this.total = total; |
| this.metadata = metadata; |
| this.unit = unit; |
| this.compactionId = compactionId; |
| this.sstables = ImmutableSet.copyOf(sstables); |
| this.targetDirectory = targetDirectory; |
| } |
| |
| public CompactionInfo(TableMetadata metadata, OperationType tasktype, long completed, long total, TimeUUID compactionId, Collection<SSTableReader> sstables, String targetDirectory) |
| { |
| this(metadata, tasktype, completed, total, Unit.BYTES, compactionId, sstables, targetDirectory); |
| } |
| |
| public CompactionInfo(TableMetadata metadata, OperationType tasktype, long completed, long total, TimeUUID compactionId, Collection<? extends SSTableReader> sstables) |
| { |
| this(metadata, tasktype, completed, total, Unit.BYTES, compactionId, sstables, null); |
| } |
| |
| /** |
| * Special compaction info where we always need to cancel the compaction - for example ViewBuilderTask where we don't know |
| * the sstables at construction |
| */ |
| public static CompactionInfo withoutSSTables(TableMetadata metadata, OperationType tasktype, long completed, long total, Unit unit, TimeUUID compactionId) |
| { |
| return withoutSSTables(metadata, tasktype, completed, total, unit, compactionId, null); |
| } |
| |
| /** |
| * Special compaction info where we always need to cancel the compaction - for example AutoSavingCache where we don't know |
| * the sstables at construction |
| */ |
| public static CompactionInfo withoutSSTables(TableMetadata metadata, OperationType tasktype, long completed, long total, Unit unit, TimeUUID compactionId, String targetDirectory) |
| { |
| return new CompactionInfo(metadata, tasktype, completed, total, unit, compactionId, ImmutableSet.of(), targetDirectory); |
| } |
| |
| /** @return A copy of this CompactionInfo with updated progress. */ |
| public CompactionInfo forProgress(long complete, long total) |
| { |
| return new CompactionInfo(metadata, tasktype, complete, total, unit, compactionId, sstables, targetDirectory); |
| } |
| |
| public Optional<String> getKeyspace() |
| { |
| return Optional.ofNullable(metadata != null ? metadata.keyspace : null); |
| } |
| |
| public Optional<String> getTable() |
| { |
| return Optional.ofNullable(metadata != null ? metadata.name : null); |
| } |
| |
| public TableMetadata getTableMetadata() |
| { |
| return metadata; |
| } |
| |
| public long getCompleted() |
| { |
| return completed; |
| } |
| |
| public long getTotal() |
| { |
| return total; |
| } |
| |
| public OperationType getTaskType() |
| { |
| return tasktype; |
| } |
| |
| public TimeUUID getTaskId() |
| { |
| return compactionId; |
| } |
| |
| public Unit getUnit() |
| { |
| return unit; |
| } |
| |
| public Set<SSTableReader> getSSTables() |
| { |
| return sstables; |
| } |
| |
| /** |
| * Get the directories this compaction could possibly write to. |
| * |
| * @return the directories that we might write to, or empty list if we don't know the metadata |
| * (like for index summary redistribution), or null if we don't have any disk boundaries |
| */ |
| public List<File> getTargetDirectories() |
| { |
| if (metadata != null && !metadata.isIndex()) |
| { |
| ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(metadata.id); |
| if (cfs != null) |
| return cfs.getDirectoriesForFiles(sstables); |
| } |
| return Collections.emptyList(); |
| } |
| |
| public String targetDirectory() |
| { |
| if (targetDirectory == null) |
| return ""; |
| |
| try |
| { |
| return new File(targetDirectory).canonicalPath(); |
| } |
| catch (Throwable t) |
| { |
| throw new RuntimeException("Unable to resolve canonical path for " + targetDirectory); |
| } |
| } |
| |
| /** |
| * Note that this estimate is based on the amount of data we have left to read - it assumes input |
| * size == output size for a compaction, which is not really true, but should most often provide a worst case |
| * remaining write size. |
| */ |
| public long estimatedRemainingWriteBytes() |
| { |
| if (unit == Unit.BYTES && tasktype.writesData) |
| return getTotal() - getCompleted(); |
| return 0; |
| } |
| |
| @Override |
| public String toString() |
| { |
| if (metadata != null) |
| { |
| return String.format("%s(%s, %s / %s %s)@%s(%s, %s)", |
| tasktype, compactionId, completed, total, unit, |
| metadata.id, metadata.keyspace, metadata.name); |
| } |
| else |
| { |
| return String.format("%s(%s, %s / %s %s)", |
| tasktype, compactionId, completed, total, unit); |
| } |
| } |
| |
| public Map<String, String> asMap() |
| { |
| Map<String, String> ret = new HashMap<String, String>(); |
| ret.put(ID, metadata != null ? metadata.id.toString() : ""); |
| ret.put(KEYSPACE, getKeyspace().orElse(null)); |
| ret.put(COLUMNFAMILY, getTable().orElse(null)); |
| ret.put(COMPLETED, Long.toString(completed)); |
| ret.put(TOTAL, Long.toString(total)); |
| ret.put(TASK_TYPE, tasktype.toString()); |
| ret.put(UNIT, unit.toString()); |
| ret.put(COMPACTION_ID, compactionId == null ? "" : compactionId.toString()); |
| ret.put(SSTABLES, Joiner.on(',').join(sstables)); |
| ret.put(TARGET_DIRECTORY, targetDirectory()); |
| return ret; |
| } |
| |
| boolean shouldStop(Predicate<SSTableReader> sstablePredicate) |
| { |
| if (sstables.isEmpty()) |
| { |
| return true; |
| } |
| return sstables.stream().anyMatch(sstablePredicate); |
| } |
| |
| public static abstract class Holder |
| { |
| private volatile boolean stopRequested = false; |
| public abstract CompactionInfo getCompactionInfo(); |
| |
| public void stop() |
| { |
| stopRequested = true; |
| } |
| |
| /** |
| * if this compaction involves several/all tables we can safely check globalCompactionsPaused |
| * in isStopRequested() below |
| */ |
| public abstract boolean isGlobal(); |
| |
| public boolean isStopRequested() |
| { |
| return stopRequested || (isGlobal() && CompactionManager.instance.isGlobalCompactionPaused()); |
| } |
| } |
| |
| public enum Unit |
| { |
| BYTES("bytes"), RANGES("token range parts"), KEYS("keys"); |
| |
| private final String name; |
| |
| Unit(String name) |
| { |
| this.name = name; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return this.name; |
| } |
| |
| public static boolean isFileSize(String unit) |
| { |
| return BYTES.toString().equals(unit); |
| } |
| } |
| } |