blob: 2db0ab8f4d2c102ba9b9ac4cfa6e94619c70c211 [file] [log] [blame]
/*
* 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.jackrabbit.oak.segment.file;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.apache.jackrabbit.oak.segment.RecordId;
import org.apache.jackrabbit.oak.segment.RecordType;
import org.apache.jackrabbit.oak.segment.SegmentId;
import org.apache.jackrabbit.oak.segment.SegmentNotFoundException;
import org.apache.jackrabbit.oak.segment.SegmentVersion;
import org.apache.jackrabbit.oak.segment.file.proc.Proc.Backend;
import org.apache.jackrabbit.oak.segment.spi.monitor.FileStoreMonitorAdapter;
import org.apache.jackrabbit.oak.segment.spi.monitor.IOMonitorAdapter;
import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveEntry;
import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveManager;
import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentArchiveReader;
import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence;
import org.apache.jackrabbit.oak.spi.state.NodeState;
class FileStoreProcBackend implements Backend {
private final AbstractFileStore fileStore;
private final SegmentNodeStorePersistence persistence;
private final SegmentArchiveManager archiveManager;
FileStoreProcBackend(AbstractFileStore fileStore, SegmentNodeStorePersistence persistence) throws IOException {
this.fileStore = fileStore;
this.persistence = persistence;
this.archiveManager = persistence.createArchiveManager(true, new IOMonitorAdapter(), new FileStoreMonitorAdapter());
}
@Override
public boolean tarExists(String name) {
try {
return archiveManager.listArchives().contains(name);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public Optional<Long> getTarSize(String name) {
try (SegmentArchiveReader reader = archiveManager.open(name)) {
return Optional.ofNullable(reader).map(SegmentArchiveReader::length);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public Iterable<String> getTarNames() {
try {
return archiveManager.listArchives();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean segmentExists(String name, String segmentId) {
try (SegmentArchiveReader reader = archiveManager.open(name)) {
if (reader == null) {
return false;
}
return segmentExists(reader, UUID.fromString(segmentId));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private boolean segmentExists(SegmentArchiveReader reader, UUID id) {
return reader.containsSegment(id.getMostSignificantBits(), id.getLeastSignificantBits());
}
@Override
public Iterable<String> getSegmentIds(String name) {
try (SegmentArchiveReader reader = archiveManager.open(name)) {
if (reader == null) {
return Collections.emptyList();
}
return getSegmentIds(reader);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Iterable<String> getSegmentIds(SegmentArchiveReader reader) {
List<String> ids = new ArrayList<>();
for (SegmentArchiveEntry entry : reader.listSegments()) {
ids.add(new UUID(entry.getMsb(), entry.getLsb()).toString());
}
return ids;
}
private Optional<org.apache.jackrabbit.oak.segment.Segment> readSegment(String id) {
return readSegment(UUID.fromString(id));
}
private Optional<org.apache.jackrabbit.oak.segment.Segment> readSegment(UUID id) {
return readSegment(fileStore.getSegmentIdProvider().newSegmentId(
id.getMostSignificantBits(),
id.getLeastSignificantBits()
));
}
private Optional<org.apache.jackrabbit.oak.segment.Segment> readSegment(SegmentId id) {
try {
return Optional.of(fileStore.readSegment(id));
} catch (SegmentNotFoundException e) {
return Optional.empty();
}
}
@Override
public Optional<Segment> getSegment(String id) {
return readSegment(id).map(segment -> new Segment() {
@Override
public int getGeneration() {
return segment.getGcGeneration().getGeneration();
}
@Override
public int getFullGeneration() {
return segment.getGcGeneration().getFullGeneration();
}
@Override
public boolean isCompacted() {
return segment.getGcGeneration().isCompacted();
}
@Override
public int getLength() {
return segment.size();
}
@Override
public int getVersion() {
return SegmentVersion.asByte(segment.getSegmentVersion());
}
@Override
public boolean isDataSegment() {
return segment.getSegmentId().isDataSegmentId();
}
@Override
public Optional<String> getInfo() {
return Optional.ofNullable(segment.getSegmentInfo());
}
});
}
@Override
public Optional<InputStream> getSegmentData(String segmentId) {
return readSegment(segmentId).map(segment -> {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
segment.writeTo(out);
} catch (IOException e) {
return null;
}
return new ByteArrayInputStream(out.toByteArray());
});
}
@Override
public Optional<Iterable<String>> getSegmentReferences(String segmentId) {
return readSegment(segmentId).map(segment -> {
List<String> references = new ArrayList<>(segment.getReferencedSegmentIdCount());
for (int i = 0; i < segment.getReferencedSegmentIdCount(); i++) {
references.add(segment.getReferencedSegmentId(i).toString());
}
return references;
});
}
@Override
public Optional<Iterable<Record>> getSegmentRecords(String segmentId) {
return readSegment(segmentId).map(segment -> {
List<Record> records = new ArrayList<>();
segment.forEachRecord((number, type, offset) -> {
records.add(new Record() {
@Override
public int getNumber() {
return number;
}
@Override
public String getSegmentId() {
return segmentId;
}
@Override
public int getOffset() {
return offset;
}
@Override
public int getAddress() {
return segment.getAddress(offset);
}
@Override
public String getType() {
return type.name();
}
@Override
public Optional<NodeState> getRoot() {
if (RecordType.NODE == type) {
RecordId id = new RecordId(segment.getSegmentId(), number);
return Optional.of(fileStore.getReader().readNode(id));
} else {
return Optional.empty();
}
}
});
});
return records;
});
}
@Override
public boolean commitExists(String handle) {
long timestamp = Long.parseLong(handle);
try (JournalReader reader = new JournalReader(persistence.getJournalFile())) {
for (JournalEntry entry : iterable(reader)) {
if (entry.getTimestamp() == timestamp) {
return true;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return false;
}
private <T> Iterable<T> iterable(Iterator<T> i) {
return () -> i;
}
@Override
public Iterable<String> getCommitHandles() {
try (JournalReader reader = new JournalReader(persistence.getJournalFile())) {
List<String> handles = new ArrayList<>();
for (JournalEntry entry : iterable(reader)) {
handles.add(Long.toString(entry.getTimestamp()));
}
return handles;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public Optional<Commit> getCommit(String handle) {
JournalEntry entry;
try (JournalReader reader = new JournalReader(persistence.getJournalFile())) {
entry = getEntry(reader, Long.parseLong(handle));
} catch (IOException e) {
throw new RuntimeException(e);
}
if (entry == null) {
return Optional.empty();
}
return Optional.of(new Commit() {
@Override
public long getTimestamp() {
return entry.getTimestamp();
}
@Override
public String getRevision() {
return entry.getRevision();
}
@Override
public Optional<NodeState> getRoot() {
RecordId id = RecordId.fromString(fileStore.getSegmentIdProvider(), entry.getRevision());
return Optional.of(fileStore.getReader().readNode(id));
}
});
}
private JournalEntry getEntry(JournalReader reader, long timestamp) {
for (JournalEntry entry : iterable(reader)) {
if (entry.getTimestamp() == timestamp) {
return entry;
}
}
return null;
}
}