blob: 786b56a85a16f2642b911274695aed01c1206367 [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;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import org.apache.jackrabbit.oak.segment.WriterCacheManager.Empty;
import org.apache.jackrabbit.oak.segment.file.FileStore;
import org.apache.jackrabbit.oak.segment.file.ReadOnlyFileStore;
import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
import org.apache.jackrabbit.oak.segment.memory.MemoryStore;
import org.jetbrains.annotations.NotNull;
/**
* Builder for building {@link DefaultSegmentWriter} instances.
* The returned instances are thread safe if {@link #withWriterPool()}
* was specified and <em>not</em> thread sage if {@link #withoutWriterPool()}
* was specified (default).
* <p>
* <em>Default:</em> calling one of the {@code build()} methods without previously
* calling one of the {@code with...()} methods returns a {@code SegmentWriter}
* as would the following chain of calls:
* <pre>
segmentWriterBuilder("name")
.with(LATEST_VERSION)
.withGeneration(0)
.withoutWriterPool()
.with(new WriterCacheManager.Default())
.build(store);
* </pre>
*/
public final class DefaultSegmentWriterBuilder {
@NotNull
private final String name;
@NotNull
private Supplier<GCGeneration> generation = Suppliers.ofInstance(GCGeneration.NULL);
private boolean pooled = false;
@NotNull
private WriterCacheManager cacheManager = new WriterCacheManager.Default();
private DefaultSegmentWriterBuilder(@NotNull String name) {
this.name = checkNotNull(name);
}
/**
* Set the {@code name} of this builder. This name will appear in the segment's
* meta data.
*/
@NotNull
public static DefaultSegmentWriterBuilder defaultSegmentWriterBuilder(@NotNull String name) {
return new DefaultSegmentWriterBuilder(name);
}
/**
* Specify the {@code generation} for the segment written by the returned
* segment writer.
* <p>
* If {@link #withoutWriterPool()} was specified all segments will be written
* at the generation that {@code generation.get()} returned at the time
* any of the {@code build()} methods is called.
* If {@link #withWriterPool()} was specified a segments will be written
* at the generation that {@code generation.get()} returns when a new segment
* is created by the returned writer.
*/
@NotNull
public DefaultSegmentWriterBuilder withGeneration(@NotNull Supplier<GCGeneration> generation) {
this.generation = checkNotNull(generation);
return this;
}
/**
* Specify the {@code generation} for the segment written by the returned
* segment writer.
*/
@NotNull
public DefaultSegmentWriterBuilder withGeneration(@NotNull GCGeneration generation) {
this.generation = Suppliers.ofInstance(checkNotNull(generation));
return this;
}
/**
* Create a {@code SegmentWriter} backed by a {@link SegmentBufferWriterPool}.
* The returned instance is thread safe.
*/
@NotNull
public DefaultSegmentWriterBuilder withWriterPool() {
this.pooled = true;
return this;
}
/**
* Create a {@code SegmentWriter} backed by a {@link SegmentBufferWriter}.
* The returned instance is <em>not</em> thread safe.
*/
@NotNull
public DefaultSegmentWriterBuilder withoutWriterPool() {
this.pooled = false;
return this;
}
/**
* Specify the {@code cacheManager} used by the returned writer.
*/
@NotNull
public DefaultSegmentWriterBuilder with(WriterCacheManager cacheManager) {
this.cacheManager = checkNotNull(cacheManager);
return this;
}
/**
* Specify that the returned writer should not use a cache.
* @see #with(WriterCacheManager)
*/
@NotNull
public DefaultSegmentWriterBuilder withoutCache() {
this.cacheManager = Empty.INSTANCE;
return this;
}
/**
* Build a {@code SegmentWriter} for a {@code FileStore}.
*/
@NotNull
public DefaultSegmentWriter build(@NotNull FileStore store) {
return new DefaultSegmentWriter(
checkNotNull(store),
store.getReader(),
store.getSegmentIdProvider(),
store.getBlobStore(),
cacheManager,
createWriter(store, pooled)
);
}
/**
* Build a {@code SegmentWriter} for a {@code ReadOnlyFileStore}.
* Attempting to write to the returned writer will cause a
* {@code UnsupportedOperationException} to be thrown.
*/
@NotNull
public DefaultSegmentWriter build(@NotNull ReadOnlyFileStore store) {
return new DefaultSegmentWriter(
checkNotNull(store),
store.getReader(),
store.getSegmentIdProvider(),
store.getBlobStore(),
cacheManager,
new WriteOperationHandler() {
@NotNull
@Override
public RecordId execute(@NotNull WriteOperation writeOperation) {
throw new UnsupportedOperationException("Cannot write to read-only store");
}
@Override
public void flush(@NotNull SegmentStore store) {
throw new UnsupportedOperationException("Cannot write to read-only store");
}
}
);
}
/**
* Build a {@code SegmentWriter} for a {@code MemoryStore}.
*/
@NotNull
public DefaultSegmentWriter build(@NotNull MemoryStore store) {
return new DefaultSegmentWriter(
checkNotNull(store),
store.getReader(),
store.getSegmentIdProvider(),
store.getBlobStore(),
cacheManager,
createWriter(store, pooled)
);
}
@NotNull
private WriteOperationHandler createWriter(@NotNull FileStore store, boolean pooled) {
if (pooled) {
return new SegmentBufferWriterPool(
store.getSegmentIdProvider(),
store.getReader(),
name,
generation
);
} else {
return new SegmentBufferWriter(
store.getSegmentIdProvider(),
store.getReader(),
name,
generation.get()
);
}
}
@NotNull
private WriteOperationHandler createWriter(@NotNull MemoryStore store, boolean pooled) {
if (pooled) {
return new SegmentBufferWriterPool(
store.getSegmentIdProvider(),
store.getReader(),
name,
generation
);
} else {
return new SegmentBufferWriter(
store.getSegmentIdProvider(),
store.getReader(),
name,
generation.get()
);
}
}
}