diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java new file mode 100644 index 0000000..9879da4 --- /dev/null +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactory.java @@ -0,0 +1,308 @@ +/* + * 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.checkState; +import static org.apache.jackrabbit.oak.osgi.OsgiUtil.lookupConfigurationThenFramework; +import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; +import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean; + +import java.io.File; +import java.io.IOException; +import java.util.Dictionary; +import java.util.Hashtable; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.jackrabbit.oak.commons.PropertiesUtil; +import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; +import org.apache.jackrabbit.oak.segment.file.FileStore; +import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder; +import org.apache.jackrabbit.oak.segment.file.FileStoreStatsMBean; +import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; +import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.apache.jackrabbit.oak.spi.state.NodeStoreProvider; +import org.apache.jackrabbit.oak.spi.state.ProxyNodeStore; +import org.apache.jackrabbit.oak.spi.whiteboard.Registration; +import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A factory allowing creation of secondary segment node stores. + *
+ * The different secondaries are distinguished by their role attribute.
+ */
+@Component(policy = ConfigurationPolicy.REQUIRE,
+ name="org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory",
+ configurationFactory=true,
+ metatype = true,
+ label = "Apache Jackrabbit Oak Segment-Tar NodeStore Factory",
+ description = "Factory allowing configuration of adjacent instances of " +
+ "NodeStore implementation based on Segment model besides a default SegmentNodeStore in same setup."
+)
+public class SegmentNodeStoreFactory extends ProxyNodeStore
+ implements SegmentStoreProvider {
+
+ public static final String NAME = "name";
+
+ @Property(
+ label = "Role",
+ description="As multiple SegmentNodeStores can be configured, this parameter defines the role " +
+ "of 'this' SegmentNodeStore."
+ )
+ public static final String ROLE = "nsProvider.role";
+
+ @Property(
+ label = "Directory",
+ description="Directory location used to store the segment tar files. If not specified then looks " +
+ "for framework property 'repository.home' otherwise use a subdirectory with name 'tarmk'"
+ )
+ public static final String DIRECTORY = "repository.home";
+
+ @Property(
+ label = "Mode",
+ description="TarMK mode (64 for memory mapping, 32 for normal file access)"
+ )
+ public static final String MODE = "tarmk.mode";
+
+ @Property(
+ intValue = 256,
+ label = "Maximum Tar File Size (MB)",
+ description = "TarMK maximum file size (MB)"
+ )
+ public static final String SIZE = "tarmk.size";
+
+ @Property(
+ intValue = 256,
+ label = "Cache size (MB)",
+ description = "Cache size for storing most recently used Segments"
+ )
+ public static final String CACHE = "cache";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private String name;
+
+ private FileStore store;
+
+ private volatile SegmentNodeStore segmentNodeStore;
+
+ private ComponentContext context;
+
+ @Reference
+ private StatisticsProvider statisticsProvider = StatisticsProvider.NOOP;
+
+ private ServiceRegistration storeRegistration;
+ private Registration fileStoreStatsMBean;
+ private WhiteboardExecutor executor;
+
+ @Override
+ protected SegmentNodeStore getNodeStore() {
+ checkState(segmentNodeStore != null, "service must be activated when used");
+ return segmentNodeStore;
+ }
+
+ private String getRole() {
+ String role = PropertiesUtil.toString(property(ROLE), null);
+ return role;
+ }
+
+ @Activate
+ public void activate(ComponentContext context) throws IOException {
+ this.context = context;
+ log.info("activate: SegmentNodeStore '"+getRole()+"' starting.");
+
+ registerNodeStore();
+ }
+
+ @Deactivate
+ public void deactivate() {
+ unregisterNodeStore();
+
+ synchronized (this) {
+ segmentNodeStore = null;
+
+ if (store != null) {
+ store.close();
+ store = null;
+ }
+ }
+ }
+
+ private synchronized void registerNodeStore() throws IOException {
+ if (registerSegmentStore()) {
+
+ if (getRole() != null) {
+ registerNodeStoreProvider();
+ return;
+ }
+
+ }
+ }
+
+ private void registerNodeStoreProvider() {
+ SegmentNodeStore.SegmentNodeStoreBuilder nodeStoreBuilder = SegmentNodeStoreBuilders.builder(store);
+ segmentNodeStore = nodeStoreBuilder.build();
+ Dictionary
+ * The different secondaries are distinguished by their role attribute.
+ */
+@Component(policy = ConfigurationPolicy.REQUIRE,
+ name="org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreFactory",
+ configurationFactory=true,
+ metatype = true,
+ label = "Apache Jackrabbit Oak Segment NodeStore Factory",
+ description = "Factory allowing configuration of adjacent instances of " +
+ "NodeStore implementation based on Segment model besides a default SegmentNodeStore in same setup."
+)
+public class SegmentNodeStoreFactory extends ProxyNodeStore
+ implements SegmentStoreProvider {
+
+ public static final String NAME = "name";
+
+ @Property(
+ label = "Role",
+ description="As multiple SegmentNodeStores can be configured, this parameter defines the role " +
+ "of 'this' SegmentNodeStore."
+ )
+ public static final String ROLE = "nsProvider.role";
+
+ @Property(
+ label = "Directory",
+ description="Directory location used to store the segment tar files. If not specified then looks " +
+ "for framework property 'repository.home' otherwise use a subdirectory with name 'tarmk'"
+ )
+ public static final String DIRECTORY = "repository.home";
+
+ @Property(
+ label = "Mode",
+ description="TarMK mode (64 for memory mapping, 32 for normal file access)"
+ )
+ public static final String MODE = "tarmk.mode";
+
+ @Property(
+ intValue = 256,
+ label = "Maximum Tar File Size (MB)",
+ description = "TarMK maximum file size (MB)"
+ )
+ public static final String SIZE = "tarmk.size";
+
+ @Property(
+ intValue = 256,
+ label = "Cache size (MB)",
+ description = "Cache size for storing most recently used Segments"
+ )
+ public static final String CACHE = "cache";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private String name;
+
+ private FileStore store;
+
+ private volatile SegmentNodeStore segmentNodeStore;
+
+ private ComponentContext context;
+
+ @Reference
+ private StatisticsProvider statisticsProvider = StatisticsProvider.NOOP;
+
+ private ServiceRegistration storeRegistration;
+ private Registration fileStoreStatsMBean;
+ private WhiteboardExecutor executor;
+
+ @Override
+ protected SegmentNodeStore getNodeStore() {
+ checkState(segmentNodeStore != null, "service must be activated when used");
+ return segmentNodeStore;
+ }
+
+ private String getRole() {
+ String role = PropertiesUtil.toString(property(ROLE), null);
+ return role;
+ }
+
+ @Activate
+ public void activate(ComponentContext context) throws IOException {
+ this.context = context;
+ log.info("activate: SegmentNodeStore '"+getRole()+"' starting.");
+
+ registerNodeStore();
+ }
+
+ @Deactivate
+ public void deactivate() {
+ unregisterNodeStore();
+
+ synchronized (this) {
+ segmentNodeStore = null;
+
+ if (store != null) {
+ store.close();
+ store = null;
+ }
+ }
+ }
+
+ private synchronized void registerNodeStore() throws IOException {
+ if (registerSegmentStore()) {
+
+ if (getRole() != null) {
+ registerNodeStoreProvider();
+ return;
+ }
+
+ }
+ }
+
+ private void registerNodeStoreProvider() {
+ SegmentNodeStore.SegmentNodeStoreBuilder nodeStoreBuilder = SegmentNodeStore.builder(store);
+ segmentNodeStore = nodeStoreBuilder.build();
+ Dictionary