Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java Fri Jul 13 13:23:24 2018 @@ -21,40 +21,9 @@ package org.apache.jackrabbit.oak.segmen import static com.google.common.base.Strings.isNullOrEmpty; import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly; -import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toBoolean; -import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toInteger; -import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toLong; -import static org.apache.jackrabbit.oak.osgi.OsgiUtil.lookupConfigurationThenFramework; -import static org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.isShared; import static org.apache.jackrabbit.oak.segment.CachingSegmentReader.DEFAULT_STRING_CACHE_MB; import static org.apache.jackrabbit.oak.segment.CachingSegmentReader.DEFAULT_TEMPLATE_CACHE_MB; import static org.apache.jackrabbit.oak.segment.SegmentCache.DEFAULT_SEGMENT_CACHE_MB; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.BACKUP_DIRECTORY; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_DISABLE_ESTIMATION; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_FORCE_TIMEOUT; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_RETRY_COUNT; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_SIZE_DELTA_ESTIMATION; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.CUSTOM_BLOB_STORE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.CUSTOM_SEGMENT_STORE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.DEFAULT_BLOB_GC_MAX_AGE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.DEFAULT_BLOB_SNAPSHOT_INTERVAL; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.GC_PROGRESS_LOG; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.MEMORY_THRESHOLD; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.MODE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.NODE_DEDUPLICATION_CACHE_SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.PAUSE_COMPACTION; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.PROP_BLOB_GC_MAX_AGE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.PROP_BLOB_SNAPSHOT_INTERVAL; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.REPOSITORY_HOME_DIRECTORY; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.RETAINED_GENERATIONS; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.SEGMENT_CACHE_SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.STANDBY; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.STRING_CACHE_SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.STRING_DEDUPLICATION_CACHE_SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.TEMPLATE_CACHE_SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.TEMPLATE_DEDUPLICATION_CACHE_SIZE; -import static org.apache.jackrabbit.oak.segment.SegmentNotFoundExceptionListener.IGNORE_SNFE; import static org.apache.jackrabbit.oak.segment.WriterCacheManager.DEFAULT_NODE_CACHE_SIZE_OSGi; import static org.apache.jackrabbit.oak.segment.WriterCacheManager.DEFAULT_STRING_CACHE_SIZE_OSGi; import static org.apache.jackrabbit.oak.segment.WriterCacheManager.DEFAULT_TEMPLATE_CACHE_SIZE_OSGi; @@ -67,996 +36,511 @@ import static org.apache.jackrabbit.oak. import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.RETRY_COUNT_DEFAULT; import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.SIZE_DELTA_ESTIMATION_DEFAULT; import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.DEFAULT_MAX_FILE_SIZE; -import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; import static org.apache.jackrabbit.oak.spi.blob.osgi.SplitBlobStoreService.ONLY_STANDALONE_TARGET; -import static org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo.getOrCreateId; -import java.io.ByteArrayInputStream; -import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import com.google.common.base.Supplier; import com.google.common.io.Closer; -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.felix.scr.annotations.ReferenceCardinality; -import org.apache.felix.scr.annotations.ReferencePolicy; -import org.apache.felix.scr.annotations.ReferencePolicyOption; -import org.apache.jackrabbit.commons.SimpleValueFactory; -import org.apache.jackrabbit.oak.api.Descriptors; -import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean; -import org.apache.jackrabbit.oak.api.jmx.CheckpointMBean; -import org.apache.jackrabbit.oak.api.jmx.FileStoreBackupRestoreMBean; -import org.apache.jackrabbit.oak.backup.impl.FileStoreBackupRestoreImpl; -import org.apache.jackrabbit.oak.cache.CacheStats; -import org.apache.jackrabbit.oak.cache.CacheStatsMBeanWrapper; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; -import org.apache.jackrabbit.oak.plugins.blob.BlobGC; -import org.apache.jackrabbit.oak.plugins.blob.BlobGCMBean; -import org.apache.jackrabbit.oak.plugins.blob.BlobGarbageCollector; -import org.apache.jackrabbit.oak.plugins.blob.BlobTrackingStore; -import org.apache.jackrabbit.oak.plugins.blob.MarkSweepGarbageCollector; -import org.apache.jackrabbit.oak.plugins.blob.SharedDataStore; -import org.apache.jackrabbit.oak.plugins.blob.datastore.BlobIdTracker; -import org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.SharedStoreRecordType; -import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions; -import org.apache.jackrabbit.oak.segment.compaction.SegmentRevisionGC; -import org.apache.jackrabbit.oak.segment.compaction.SegmentRevisionGCMBean; -import org.apache.jackrabbit.oak.segment.file.FileStore; -import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder; -import org.apache.jackrabbit.oak.segment.file.FileStoreGCMonitor; -import org.apache.jackrabbit.oak.segment.file.FileStoreStatsMBean; -import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; -import org.apache.jackrabbit.oak.segment.file.MetricsIOMonitor; -import org.apache.jackrabbit.oak.segment.file.tar.SegmentTarReader; import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence; -import org.apache.jackrabbit.oak.segment.util.RoleUtils; import org.apache.jackrabbit.oak.spi.blob.BlobStore; -import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore; -import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo; -import org.apache.jackrabbit.oak.spi.commit.ObserverTracker; -import org.apache.jackrabbit.oak.spi.descriptors.GenericDescriptors; -import org.apache.jackrabbit.oak.spi.gc.GCMonitor; -import org.apache.jackrabbit.oak.spi.gc.GCMonitorTracker; -import org.apache.jackrabbit.oak.spi.state.NodeStore; -import org.apache.jackrabbit.oak.spi.state.RevisionGC; -import org.apache.jackrabbit.oak.spi.state.RevisionGCMBean; -import org.apache.jackrabbit.oak.spi.whiteboard.AbstractServiceTracker; -import org.apache.jackrabbit.oak.spi.whiteboard.Registration; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; -import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor; -import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils; -import org.apache.jackrabbit.oak.stats.Clock; import org.apache.jackrabbit.oak.stats.StatisticsProvider; -import org.osgi.framework.Constants; +import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An OSGi wrapper for the segment node store. */ -@Component(policy = ConfigurationPolicy.REQUIRE, - metatype = true, - label = "Oak Segment Tar NodeStore service", - description = "Apache Jackrabbit Oak NodeStore implementation based on the segment model. " + - "For configuration refer to http://jackrabbit.apache.org/oak/docs/osgi_config.html#SegmentNodeStore. " + - "Note that for system stability purpose it is advisable to not change these settings " + - "at runtime. Instead the config change should be done via file system based config " + - "file and this view should ONLY be used to determine which options are supported." -) +@Component(configurationPolicy = ConfigurationPolicy.REQUIRE) +@Designate(ocd = SegmentNodeStoreService.Configuration.class) public class SegmentNodeStoreService { private static final Logger log = LoggerFactory.getLogger(SegmentNodeStoreService.class); - @Property( - label = "Repository Home Directory", - description = "Path on the file system where repository data will be stored. " - + "Defaults to the value of the framework property 'repository.home' or to 'repository' " - + "if that is neither specified." - ) + // TODO(frm) This is only exposed to tests. Should it be removed? + public static final String CUSTOM_BLOB_STORE = "customBlobStore"; + + // TODO(frm) This is only exposed to tests. Should it be removed? public static final String REPOSITORY_HOME_DIRECTORY = "repository.home"; - @Property( - label = "Mode", - description = "TarMK mode (64 for memory mapped file access, 32 for normal file access). " + - "Default value is taken from the 'sun.arch.data.model' system property." + private static final long DEFAULT_BLOB_SNAPSHOT_INTERVAL = 12 * 60 * 60; + + private static final long DEFAULT_BLOB_GC_MAX_AGE = 24 * 60 * 60; + + @ObjectClassDefinition( + name = "Oak Segment Tar NodeStore service", + description = "Apache Jackrabbit Oak NodeStore implementation based on " + + "the segment model. For configuration refer to http://jackrabbit.apache.org/oak/docs/osgi_config.html#SegmentNodeStore. " + + "Note that for system stability purpose it is advisable to not " + + "change these settings at runtime. Instead the config change should " + + "be done via file system based config file and this view should ONLY " + + "be used to determine which options are supported." ) - public static final String MODE = "tarmk.mode"; + @interface Configuration { + + @AttributeDefinition( + name = "Repository Home Directory", + description = "Path on the file system where repository data will be stored. " + + "Defaults to the value of the framework property 'repository.home' or to 'repository' " + + "if that is neither specified." + ) + String repository_home() default "repository"; - @Property( - intValue = DEFAULT_MAX_FILE_SIZE, - label = "Maximum tar file size (MB)", + @AttributeDefinition( + name = "Mode", + description = "TarMK mode (64 for memory mapped file access, 32 for normal file access). " + + "Default value is taken from the 'sun.arch.data.model' system property." + ) + String tarmk_mode() default ""; + + @AttributeDefinition( + name = "Maximum tar file size (MB)", description = "The maximum size of the tar files in megabytes. " + - "Default value is '" + DEFAULT_MAX_FILE_SIZE + "'." - ) - public static final String SIZE = "tarmk.size"; + "Default value is '" + DEFAULT_MAX_FILE_SIZE + "'." + ) + int tarmk_size() default DEFAULT_MAX_FILE_SIZE; - @Property( - intValue = DEFAULT_SEGMENT_CACHE_MB, - label = "Segment cache size (MB)", + @AttributeDefinition( + name = "Segment cache size (MB)", description = "Cache size for storing most recently used segments in megabytes. " + - "Default value is '" + DEFAULT_SEGMENT_CACHE_MB + "'." - ) - public static final String SEGMENT_CACHE_SIZE = "segmentCache.size"; + "Default value is '" + DEFAULT_SEGMENT_CACHE_MB + "'." + ) + int segmentCache_size() default DEFAULT_SEGMENT_CACHE_MB; - @Property( - intValue = DEFAULT_STRING_CACHE_MB, - label = "String cache size (MB)", + @AttributeDefinition( + name = "String cache size (MB)", description = "Cache size for storing most recently used strings in megabytes. " + - "Default value is '" + DEFAULT_STRING_CACHE_MB + "'." - ) - public static final String STRING_CACHE_SIZE = "stringCache.size"; + "Default value is '" + DEFAULT_STRING_CACHE_MB + "'." + ) + int stringCache_size() default DEFAULT_STRING_CACHE_MB; - @Property( - intValue = DEFAULT_TEMPLATE_CACHE_MB, - label = "Template cache size (MB)", + @AttributeDefinition( + name = "Template cache size (MB)", description = "Cache size for storing most recently used templates in megabytes. " + - "Default value is '" + DEFAULT_TEMPLATE_CACHE_MB + "'." - ) - public static final String TEMPLATE_CACHE_SIZE = "templateCache.size"; + "Default value is '" + DEFAULT_TEMPLATE_CACHE_MB + "'." + ) + int templateCache_size() default DEFAULT_TEMPLATE_CACHE_MB; - @Property( - intValue = DEFAULT_STRING_CACHE_SIZE_OSGi, - label = "String deduplication cache size (#items)", + @AttributeDefinition( + name = "String deduplication cache size (#items)", description = "Maximum number of strings to keep in the deduplication cache. " + - "Default value is '" + DEFAULT_STRING_CACHE_SIZE_OSGi + "'." - ) - public static final String STRING_DEDUPLICATION_CACHE_SIZE = "stringDeduplicationCache.size"; + "Default value is '" + DEFAULT_STRING_CACHE_SIZE_OSGi + "'." + ) + int stringDeduplicationCache_size() default DEFAULT_STRING_CACHE_SIZE_OSGi; - @Property( - intValue = DEFAULT_TEMPLATE_CACHE_SIZE_OSGi, - label = "Template deduplication cache size (#items)", + @AttributeDefinition( + name = "Template deduplication cache size (#items)", description = "Maximum number of templates to keep in the deduplication cache. " + - "Default value is '" + DEFAULT_TEMPLATE_CACHE_SIZE_OSGi + "'." - ) - public static final String TEMPLATE_DEDUPLICATION_CACHE_SIZE = "templateDeduplicationCache.size"; + "Default value is '" + DEFAULT_TEMPLATE_CACHE_SIZE_OSGi + "'." + ) + int templateDeduplicationCache_size() default DEFAULT_TEMPLATE_CACHE_SIZE_OSGi; - @Property( - intValue = DEFAULT_NODE_CACHE_SIZE_OSGi, - label = "Node deduplication cache size (#items)", + @AttributeDefinition( + name = "Node deduplication cache size (#items)", description = "Maximum number of node to keep in the deduplication cache. If the supplied " + - "value is not a power of 2, it will be rounded up to the next power of 2. " + - "Default value is '" + DEFAULT_NODE_CACHE_SIZE_OSGi + "'." - ) - public static final String NODE_DEDUPLICATION_CACHE_SIZE = "nodeDeduplicationCache.size"; + "value is not a power of 2, it will be rounded up to the next power of 2. " + + "Default value is '" + DEFAULT_NODE_CACHE_SIZE_OSGi + "'." + ) + int nodeDeduplicationCache_size() default DEFAULT_NODE_CACHE_SIZE_OSGi; - @Property( - boolValue = PAUSE_DEFAULT, - label = "Pause compaction", + @AttributeDefinition( + name = "Pause compaction", description = "When set to true the compaction phase is skipped during garbage collection. " + - "Default value is '" + PAUSE_DEFAULT + "'." - ) - public static final String PAUSE_COMPACTION = "pauseCompaction"; + "Default value is '" + PAUSE_DEFAULT + "'." + ) + boolean pauseCompaction() default PAUSE_DEFAULT; - @Property( - intValue = RETRY_COUNT_DEFAULT, - label = "Compaction retries", + @AttributeDefinition( + name = "Compaction retries", description = "Number of tries to compact concurrent commits on top of already " + - "compacted commits. " + - "Default value is '" + RETRY_COUNT_DEFAULT + "'." - ) - public static final String COMPACTION_RETRY_COUNT = "compaction.retryCount"; + "compacted commits. " + + "Default value is '" + RETRY_COUNT_DEFAULT + "'." + ) + int compaction_retryCount() default RETRY_COUNT_DEFAULT; - @Property( - intValue = FORCE_TIMEOUT_DEFAULT, - label = "Force compaction timeout", + @AttributeDefinition( + name = "Force compaction timeout", description = "Number of seconds to attempt to force compact concurrent commits on top " + - "of already compacted commits after the maximum number of retries has been " + - "reached. Forced compaction tries to acquire an exclusive write lock on the " + - "node store, blocking concurrent write access as long as the lock is held. " + - "Default value is '" + FORCE_TIMEOUT_DEFAULT + "'." - ) - public static final String COMPACTION_FORCE_TIMEOUT = "compaction.force.timeout"; + "of already compacted commits after the maximum number of retries has been " + + "reached. Forced compaction tries to acquire an exclusive write lock on the " + + "node store, blocking concurrent write access as long as the lock is held. " + + "Default value is '" + FORCE_TIMEOUT_DEFAULT + "'." + ) + int compaction_force_timeout() default FORCE_TIMEOUT_DEFAULT; - @Property( - longValue = SIZE_DELTA_ESTIMATION_DEFAULT, - label = "Garbage collection repository size threshold", + @AttributeDefinition( + name = "Garbage collection repository size threshold", description = "Garbage collection will be skipped unless the repository grew at least by " + - "the number of bytes specified. " + - "Default value is '" + SIZE_DELTA_ESTIMATION_DEFAULT + "'." - ) - public static final String COMPACTION_SIZE_DELTA_ESTIMATION = "compaction.sizeDeltaEstimation"; + "the number of bytes specified. " + + "Default value is '" + SIZE_DELTA_ESTIMATION_DEFAULT + "'." + ) + long compaction_sizeDeltaEstimation() default SIZE_DELTA_ESTIMATION_DEFAULT; - @Property( - boolValue = DISABLE_ESTIMATION_DEFAULT, - label = "Disable estimation phase", + @AttributeDefinition( + name = "Disable estimation phase", description = "Disables the estimation phase allowing garbage collection to run unconditionally. " + - "Default value is '" + DISABLE_ESTIMATION_DEFAULT + "'." - ) - public static final String COMPACTION_DISABLE_ESTIMATION = "compaction.disableEstimation"; + "Default value is '" + DISABLE_ESTIMATION_DEFAULT + "'." + ) + boolean compaction_disableEstimation() default DISABLE_ESTIMATION_DEFAULT; - @Property( - intValue = RETAINED_GENERATIONS_DEFAULT, - label = "Compaction retained generations", + @AttributeDefinition( + name = "Compaction retained generations", description = "Number of segment generations to retain during garbage collection. " + "The number of generations defaults to " + RETAINED_GENERATIONS_DEFAULT + " and " + "can't be changed. This configuration option is considered deprecated " + "and will be removed in the future." - ) - public static final String RETAINED_GENERATIONS = "compaction.retainedGenerations"; + ) + int compaction_retainedGenerations() default RETAINED_GENERATIONS_DEFAULT; - @Property( - intValue = MEMORY_THRESHOLD_DEFAULT, - label = "Compaction memory threshold", + @AttributeDefinition( + name = "Compaction memory threshold", description = "Threshold of available heap memory in percent of total heap memory below " + - "which the compaction phase is canceled. 0 disables heap memory monitoring. " + - "Default value is '" + MEMORY_THRESHOLD_DEFAULT + "'." - ) - public static final String MEMORY_THRESHOLD = "compaction.memoryThreshold"; + "which the compaction phase is canceled. 0 disables heap memory monitoring. " + + "Default value is '" + MEMORY_THRESHOLD_DEFAULT + "'." + ) + int compaction_memoryThreshold() default MEMORY_THRESHOLD_DEFAULT; - @Property( - longValue = GC_PROGRESS_LOG_DEFAULT, - label = "Compaction progress log", + @AttributeDefinition( + name = "Compaction progress log", description = "The number of nodes compacted after which a status message is logged. " + - "-1 disables progress logging. " + - "Default value is '" + GC_PROGRESS_LOG_DEFAULT + "'." - ) - public static final String GC_PROGRESS_LOG = "compaction.progressLog"; + "-1 disables progress logging. " + + "Default value is '" + GC_PROGRESS_LOG_DEFAULT + "'." + ) + long compaction_progressLog() default GC_PROGRESS_LOG_DEFAULT; - @Property( - boolValue = false, - label = "Standby mode", + @AttributeDefinition( + name = "Standby mode", description = "Flag indicating this component will not register as a NodeStore but as a " + - "NodeStoreProvider instead. " + - "Default value is 'false'." - ) - public static final String STANDBY = "standby"; + "NodeStoreProvider instead. " + + "Default value is 'false'." + ) + boolean standby() default false; - @Property(boolValue = false, - label = "Custom blob store", + @AttributeDefinition( + name = "Custom blob store", description = "Boolean value indicating that a custom BlobStore is used for storing " + - "large binary values." - ) - public static final String CUSTOM_BLOB_STORE = "customBlobStore"; + "large binary values." + ) + boolean customBlobStore() default false; - @Property(boolValue = false, - label = "Custom segment store", + @AttributeDefinition( + name = "Custom segment store", description = "Boolean value indicating that a custom (non-tar) segment store is used" - ) - public static final String CUSTOM_SEGMENT_STORE = "customSegmentStore"; + ) + boolean customSegmentStore() default false; - @Property( - label = "Backup directory", + @AttributeDefinition( + name = "Backup directory", description = "Directory (relative to current working directory) for storing repository backups. " + - "Defaults to 'repository.home/segmentstore-backup'." - ) - public static final String BACKUP_DIRECTORY = "repository.backup.dir"; + "Defaults to 'repository.home/segmentstore-backup'." + ) + String repository_backup_dir() default ""; + + @AttributeDefinition( + name = "Blob gc max age (in secs)", + description = "The blob garbage collection logic will only consider those blobs which " + + "are not accessed recently (currentTime - lastModifiedTime > blobGcMaxAgeInSecs). " + + "For example with the default setting only those blobs which have been created " + + "at least 24 hours ago will be considered for garbage collection. " + + "Default value is '" + DEFAULT_BLOB_GC_MAX_AGE + "'." + ) + long blobGcMaxAgeInSecs() default DEFAULT_BLOB_GC_MAX_AGE; + + @AttributeDefinition( + name = "Blob tracking snapshot interval", + description = "Interval in seconds in which snapshots of locally tracked blob ids are " + + "taken and synchronized with the blob store. This should be configured to be " + + "less than the frequency of blob garbage collection so that deletions during blob " + + "garbage collection can be accounted for in the next garbage collection execution. " + + "Default value is '" + DEFAULT_BLOB_SNAPSHOT_INTERVAL + "'." + ) + long blobTrackSnapshotIntervalInSecs() default DEFAULT_BLOB_SNAPSHOT_INTERVAL; + + } @Reference( - cardinality = ReferenceCardinality.OPTIONAL_UNARY, - policy = ReferencePolicy.STATIC, - policyOption = ReferencePolicyOption.GREEDY, - target = ONLY_STANDALONE_TARGET + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.STATIC, + policyOption = ReferencePolicyOption.GREEDY, + target = ONLY_STANDALONE_TARGET ) private volatile BlobStore blobStore; @Reference( - cardinality = ReferenceCardinality.OPTIONAL_UNARY, - policy = ReferencePolicy.STATIC, - policyOption = ReferencePolicyOption.GREEDY + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.STATIC, + policyOption = ReferencePolicyOption.GREEDY ) private volatile SegmentNodeStorePersistence segmentStore; @Reference private StatisticsProvider statisticsProvider = StatisticsProvider.NOOP; - - private Closer closer; - /** - * Blob modified before this time duration would be considered for Blob GC - */ - static final long DEFAULT_BLOB_GC_MAX_AGE = 24 * 60 * 60; - - @Property(longValue = DEFAULT_BLOB_GC_MAX_AGE, - label = "Blob gc max age (in secs)", - description = "The blob garbage collection logic will only consider those blobs which " + - "are not accessed recently (currentTime - lastModifiedTime > blobGcMaxAgeInSecs). " + - "For example with the default setting only those blobs which have been created " + - "at least 24 hours ago will be considered for garbage collection. " + - "Default value is '" + DEFAULT_BLOB_GC_MAX_AGE + "'." - ) - public static final String PROP_BLOB_GC_MAX_AGE = "blobGcMaxAgeInSecs"; - - /** - * Default interval for taking snapshots of locally tracked blob ids. - */ - static final long DEFAULT_BLOB_SNAPSHOT_INTERVAL = 12 * 60 * 60; - - @Property(longValue = DEFAULT_BLOB_SNAPSHOT_INTERVAL, - label = "Blob tracking snapshot interval", - description = "Interval in seconds in which snapshots of locally tracked blob ids are " + - "taken and synchronized with the blob store. This should be configured to be " + - "less than the frequency of blob garbage collection so that deletions during blob " + - "garbage collection can be accounted for in the next garbage collection execution. " + - "Default value is '" + DEFAULT_BLOB_SNAPSHOT_INTERVAL + "'." - ) - public static final String PROP_BLOB_SNAPSHOT_INTERVAL = "blobTrackSnapshotIntervalInSecs"; + private final Closer closer = Closer.create(); @Activate - public void activate(ComponentContext context) throws IOException { - Configuration configuration = new Configuration(context); - if (blobStore == null && configuration.hasCustomBlobStore()) { - log.info("BlobStore enabled. SegmentNodeStore will be initialized once the blob " + - "store becomes available"); - return; - } - if (segmentStore == null && configuration.hasCustomSegmentStore()) { - log.info("customSegmentStore enabled. SegmentNodeStore will be initialized once the custom segment " + - "store becomes available"); - return; - } - closer = Closer.create(); + public void activate(ComponentContext context, Configuration configuration) throws IOException { OsgiWhiteboard whiteboard = new OsgiWhiteboard(context.getBundleContext()); - registerSegmentStore(context, blobStore, segmentStore, statisticsProvider, closer, whiteboard, null, true); + registerSegmentStore(context, configuration, blobStore, segmentStore, statisticsProvider, closer, whiteboard, log); } - /** - * Configures and registers a new SegmentNodeStore instance together will - * all required components. Anything that must be disposed of (like - * registered services or MBeans) will be registered via the - * {@code registration} parameter. - * - * @param context An instance of {@link ComponentContext}. - * @param blobStore An instance of {@link BlobStore}. It can be - * {@code null}. - * @param segmentStore An instance of {@link SegmentNodeStorePersistence}. It can be - * {@code null}. - * @param statisticsProvider An instance of {@link StatisticsProvider}. - * @param closer An instance of {@link Closer}. It will be used - * to track every registered service or - * component. - * @param whiteboard An instance of {@link Whiteboard}. It will be - * used to register services in the OSGi - * framework. - * @param role The role of this component. It can be {@code - * null}. - * @param descriptors Determines if repository descriptors related to - * discovery services should be registered. - * @return A configured {@link SegmentNodeStore}, or {@code null} if the - * setup failed. - * @throws IOException In case an unrecoverable error occurs. - */ - static SegmentNodeStore registerSegmentStore( - @Nonnull ComponentContext context, - @Nullable BlobStore blobStore, - @Nullable SegmentNodeStorePersistence segmentStore, - @Nonnull StatisticsProvider statisticsProvider, - @Nonnull Closer closer, - @Nonnull Whiteboard whiteboard, - @Nullable String role, - boolean descriptors + private static SegmentNodeStore registerSegmentStore( + ComponentContext context, + Configuration configuration, + BlobStore blobStore, + SegmentNodeStorePersistence segmentStore, + StatisticsProvider statisticsProvider, + Closer closer, + Whiteboard whiteboard, + Logger logger ) throws IOException { - Configuration configuration = new Configuration(context, role); - Closeables closeables = new Closeables(closer); - Registrations registrations = new Registrations(whiteboard, role); - - // Listen for GCMonitor services - GCMonitor gcMonitor = GCMonitor.EMPTY; - - if (configuration.isPrimarySegmentStore()) { - GCMonitorTracker tracker = new GCMonitorTracker(); - tracker.start(whiteboard); - closeables.add(tracker); - gcMonitor = tracker; - } - - // Create the gc options - if (configuration.getCompactionGainThreshold() != null) { - log.warn("Detected deprecated flag 'compaction.gainThreshold'. " - + "Please use 'compaction.sizeDeltaEstimation' instead and " - + "'compaction.disableEstimation' to disable estimation."); - } - if (configuration.getRetainedGenerations() != RETAINED_GENERATIONS_DEFAULT) { - log.warn( - "The number of retained generations defaults to {} and can't be " + - "changed. This configuration option is considered deprecated " + - "and will be removed in the future.", - RETAINED_GENERATIONS_DEFAULT - ); - } - SegmentGCOptions gcOptions = new SegmentGCOptions(configuration.getPauseCompaction(), configuration.getRetryCount(), configuration.getForceCompactionTimeout()) - .setGcSizeDeltaEstimation(configuration.getSizeDeltaEstimation()) - .setMemoryThreshold(configuration.getMemoryThreshold()) - .setEstimationDisabled(configuration.getDisableEstimation()) - .setGCLogInterval(configuration.getGCProcessLog()); - if (configuration.isStandbyInstance()) { - gcOptions.setRetainedGenerations(1); - } - - // Build the FileStore - FileStoreBuilder builder = fileStoreBuilder(configuration.getSegmentDirectory()) - .withSegmentCacheSize(configuration.getSegmentCacheSize()) - .withStringCacheSize(configuration.getStringCacheSize()) - .withTemplateCacheSize(configuration.getTemplateCacheSize()) - .withStringDeduplicationCacheSize(configuration.getStringDeduplicationCacheSize()) - .withTemplateDeduplicationCacheSize(configuration.getTemplateDeduplicationCacheSize()) - .withNodeDeduplicationCacheSize(configuration.getNodeDeduplicationCacheSize()) - .withMaxFileSize(configuration.getMaxFileSize()) - .withMemoryMapping(configuration.getMemoryMapping()) - .withGCMonitor(gcMonitor) - .withIOMonitor(new MetricsIOMonitor(statisticsProvider)) - .withIOLogging(LoggerFactory.getLogger(SegmentTarReader.class)) - .withStatisticsProvider(statisticsProvider) - .withGCOptions(gcOptions); - - if (configuration.hasCustomBlobStore() && blobStore != null) { - log.info("Initializing SegmentNodeStore with BlobStore [{}]", blobStore); - builder.withBlobStore(blobStore); - } - - if (configuration.hasCustomSegmentStore() && segmentStore != null) { - log.info("Initializing SegmentNodeStore with custom persistence [{}]", segmentStore); - builder.withCustomPersistence(segmentStore); - } - - if (configuration.isStandbyInstance()) { - builder.withSnfeListener(IGNORE_SNFE); - } - - final FileStore store; - try { - store = builder.build(); - } catch (InvalidFileStoreVersionException e) { - log.error("The storage format is not compatible with this version of Oak Segment Tar", e); - return null; - } - // store should be closed last - closeables.add(store); - - // Listen for Executor services on the whiteboard - - WhiteboardExecutor executor = new WhiteboardExecutor(); - executor.start(whiteboard); - closeables.add(executor); - - // Expose stats about the segment cache - - CacheStatsMBean segmentCacheStats = addRoleToName(store.getSegmentCacheStats(), role); - closeables.add(registrations.registerMBean( - CacheStatsMBean.class, - segmentCacheStats, - CacheStats.TYPE, - segmentCacheStats.getName() - )); - - // Expose stats about the string and template caches - - CacheStatsMBean stringCacheStats = addRoleToName(store.getStringCacheStats(), role); - closeables.add(registrations.registerMBean( - CacheStatsMBean.class, - stringCacheStats, - CacheStats.TYPE, - stringCacheStats.getName() - )); - - CacheStatsMBean templateCacheStats = addRoleToName(store.getTemplateCacheStats(), role); - closeables.add(registrations.registerMBean( - CacheStatsMBean.class, - templateCacheStats, - CacheStats.TYPE, - templateCacheStats.getName() - )); - - WriterCacheManager cacheManager = builder.getCacheManager(); - CacheStatsMBean stringDeduplicationCacheStats = addRoleToName(cacheManager.getStringCacheStats(), role); - if (stringDeduplicationCacheStats != null) { - closeables.add(registrations.registerMBean( - CacheStatsMBean.class, - stringDeduplicationCacheStats, - CacheStats.TYPE, - stringDeduplicationCacheStats.getName() - )); - } - - CacheStatsMBean templateDeduplicationCacheStats = addRoleToName(cacheManager.getTemplateCacheStats(), role); - if (templateDeduplicationCacheStats != null) { - closeables.add(registrations.registerMBean( - CacheStatsMBean.class, - templateDeduplicationCacheStats, - CacheStats.TYPE, - templateDeduplicationCacheStats.getName() - )); - } - - CacheStatsMBean nodeDeduplicationCacheStats = addRoleToName(cacheManager.getNodeCacheStats(), role); - if (nodeDeduplicationCacheStats != null) { - closeables.add(registrations.registerMBean( - CacheStatsMBean.class, - nodeDeduplicationCacheStats, - CacheStats.TYPE, - nodeDeduplicationCacheStats.getName() - )); - } - - // Expose an MBean to managing and monitoring garbage collection - final FileStoreGCMonitor monitor = new FileStoreGCMonitor(Clock.SIMPLE); - closeables.add(registrations.register( - GCMonitor.class, - monitor - )); - if (!configuration.isStandbyInstance()) { - closeables.add(registrations.registerMBean( - SegmentRevisionGC.class, - new SegmentRevisionGCMBean(store, gcOptions, monitor), - SegmentRevisionGC.TYPE, - "Segment node store revision garbage collection" - )); - } - - Runnable cancelGC = new Runnable() { - - @Override - public void run() { - store.cancelGC(); - } - - }; - Supplier<String> statusMessage = new Supplier<String>() { - - @Override - public String get() { - return monitor.getStatus(); - } - - }; - closeables.add(registrations.registerMBean( - RevisionGCMBean.class, - new RevisionGC(store.getGCRunner(), cancelGC, statusMessage, executor), - RevisionGCMBean.TYPE, - "Revision garbage collection" - )); - - // Expose statistics about the FileStore - - closeables.add(registrations.registerMBean( - FileStoreStatsMBean.class, - store.getStats(), - FileStoreStatsMBean.TYPE, - "FileStore statistics" - )); - - // register segment node store - - SegmentNodeStore.SegmentNodeStoreBuilder segmentNodeStoreBuilder = SegmentNodeStoreBuilders.builder(store).withStatisticsProvider(statisticsProvider); - if (configuration.isStandbyInstance() || !configuration.isPrimarySegmentStore()) { - segmentNodeStoreBuilder.dispatchChanges(false); - } - SegmentNodeStore segmentNodeStore = segmentNodeStoreBuilder.build(); - - if (configuration.isPrimarySegmentStore()) { - ObserverTracker observerTracker = new ObserverTracker(segmentNodeStore); - observerTracker.start(context.getBundleContext()); - closeables.add(observerTracker); - } - - if (configuration.isPrimarySegmentStore()) { - closeables.add(registrations.registerMBean( - CheckpointMBean.class, - new SegmentCheckpointMBean(segmentNodeStore), - CheckpointMBean.TYPE, - "Segment node store checkpoint management" - )); - } - - if (descriptors) { - // ensure a clusterId is initialized - // and expose it as 'oak.clusterid' repository descriptor - GenericDescriptors clusterIdDesc = new GenericDescriptors(); - clusterIdDesc.put( - ClusterRepositoryInfo.OAK_CLUSTERID_REPOSITORY_DESCRIPTOR_KEY, - new SimpleValueFactory().createValue(getOrCreateId(segmentNodeStore)), - true, - false - ); - closeables.add(registrations.register(Descriptors.class, clusterIdDesc)); - // Register "discovery lite" descriptors - closeables.add(registrations.register(Descriptors.class, new SegmentDiscoveryLiteDescriptors(segmentNodeStore))); - } - - // If a shared data store register the repo id in the data store - if (configuration.isPrimarySegmentStore() && isShared(blobStore)) { - SharedDataStore sharedDataStore = (SharedDataStore) blobStore; - try { - sharedDataStore.addMetadataRecord(new ByteArrayInputStream(new byte[0]), SharedStoreRecordType.REPOSITORY.getNameFromId(getOrCreateId(segmentNodeStore))); - } catch (Exception e) { - throw new IOException("Could not register a unique repositoryId", e); - } - if (blobStore instanceof BlobTrackingStore) { - BlobTrackingStore trackingStore = (BlobTrackingStore) blobStore; - if (trackingStore.getTracker() != null) { - trackingStore.getTracker().close(); - } - trackingStore.addTracker(new BlobIdTracker(configuration.getRepositoryHome(), getOrCreateId(segmentNodeStore), configuration.getBlobSnapshotInterval(), sharedDataStore)); - } - } + return SegmentNodeStoreRegistrar.registerSegmentNodeStore(new SegmentNodeStoreRegistrar.Configuration() { - if (configuration.isPrimarySegmentStore() && blobStore instanceof GarbageCollectableBlobStore) { - BlobGarbageCollector gc = new MarkSweepGarbageCollector( - new SegmentBlobReferenceRetriever(store), - (GarbageCollectableBlobStore) blobStore, - executor, - TimeUnit.SECONDS.toMillis(configuration.getBlobGcMaxAge()), - getOrCreateId(segmentNodeStore), - whiteboard, - statisticsProvider - ); - closeables.add(registrations.registerMBean( - BlobGCMBean.class, - new BlobGC(gc, executor), - BlobGCMBean.TYPE, - "Segment node store blob garbage collection" - )); - } - - // Expose an MBean for backup/restore operations - - closeables.add(registrations.registerMBean( - FileStoreBackupRestoreMBean.class, - new FileStoreBackupRestoreImpl( - segmentNodeStore, - store.getRevisions(), - store.getReader(), - configuration.getBackupDirectory(), - executor - ), - FileStoreBackupRestoreMBean.TYPE, - "Segment node store backup/restore" - )); - - // Expose statistics about the SegmentNodeStore - - closeables.add(registrations.registerMBean( - SegmentNodeStoreStatsMBean.class, - segmentNodeStore.getStats(), - SegmentNodeStoreStatsMBean.TYPE, - "SegmentNodeStore statistics" - )); - - if (configuration.isPrimarySegmentStore()) { - log.info("Primary SegmentNodeStore initialized"); - } else { - log.info("Secondary SegmentNodeStore initialized, role={}", role); - } - - // Register a factory service to expose the FileStore - closeables.add(registrations.register( - SegmentStoreProvider.class, - new DefaultSegmentStoreProvider(store) - )); - - if (configuration.isStandbyInstance()) { - return segmentNodeStore; - } - - if (configuration.isPrimarySegmentStore()) { - Map<String, Object> props = new HashMap<String, Object>(); - props.put(Constants.SERVICE_PID, SegmentNodeStore.class.getName()); - props.put("oak.nodestore.description", new String[] {"nodeStoreType=segment"}); - closeables.add(registrations.register(NodeStore.class, segmentNodeStore, props)); - } + int roundToNextPowerOfTwo(int size) { + return 1 << (32 - Integer.numberOfLeadingZeros(Math.max(0, size - 1))); + } - return segmentNodeStore; - } + String getMode() { + String mode = configuration.tarmk_mode(); + if (isNullOrEmpty(mode)) { + return System.getProperty("tarmk.mode", System.getProperty("sun.arch.data.model", "32")); + } + return mode; + } - @Deactivate - public void deactivate() { - closeQuietly(closer); - closer = null; - } + int getCacheSize(String name, int otherwise) { + Integer size = Integer.getInteger(name); + if (size != null) { + return size; + } + return otherwise; + } - private static CacheStatsMBean addRoleToName(CacheStatsMBean cacheStatsMBean, String role) { - return new CacheStatsMBeanWrapper(cacheStatsMBean) { @Override - public String getName() { - return RoleUtils.maybeAppendRole(super.getName(), role); + public boolean isPrimarySegmentStore() { + return true; } - }; - } -} - -/** - * Encapsulates a {@link Closer} and makes it easier to track the lifecycle - * of entities that can be disposed. - */ -class Closeables implements Closeable { - - private final Closer closer; - - Closeables(Closer closer) { - this.closer = closer; - } - - void add(Closeable c) { - closer.register(c); - } - - void add(final AbstractServiceTracker<?> t) { - add(new Closeable() { @Override - public void close() { - t.stop(); + public boolean isSecondarySegmentStore() { + return false; } - }); - } - - void add(final Registration r) { - add(new Closeable() { - @Override - public void close() { - r.unregister(); + public boolean isStandbyInstance() { + return configuration.standby(); } - }); - } - - void add(final ObserverTracker t) { - add(new Closeable() { - @Override - public void close() { - t.stop(); + public String getRole() { + return null; } - }); - } - - @Override - public void close() throws IOException { - closer.close(); - } - -} - -/** - * Allows simple access to the configuration of this component. Provides - * default values for unspecified properties and type conversion. - */ -class Configuration { - - private static int roundToNextPowerOfTwo(int size) { - return 1 << (32 - Integer.numberOfLeadingZeros(Math.max(0, size - 1))); - } - - private final ComponentContext context; - - private final String role; - - Configuration(ComponentContext context) { - this(context, null); - } - - Configuration(ComponentContext context, String role) { - this.context = context; - this.role = role; - } - - String property(String name) { - return lookupConfigurationThenFramework(context, name); - } - - /** - * Chooses repository home directory name based on <b>repository.home</b> - * property, defaulting to <b>repository</b> if property is not set. - * - * @return repository home directory name. - */ - String getRepositoryHome() { - String root = property(REPOSITORY_HOME_DIRECTORY); - if (isNullOrEmpty(root)) { - return "repository"; - } - return root; - } - - /** - * Creates a new sub-directory relative to {@link #getRepositoryHome()} for - * storing segments. - * - * @return directory for storing segments. - */ - File getSegmentDirectory() { - return new File(getRepositoryHome(), appendRole("segmentstore")); - } - - /** - * Creates a new sub-directory relative to {@link #getRepositoryHome()} for - * storing repository backups. - * - * @return directory for storing repository backups. - */ - File getBackupDirectory() { - String backupDirectory = property(BACKUP_DIRECTORY); - if (backupDirectory != null) { - return new File(backupDirectory); - } - return new File(getRepositoryHome(), appendRole("segmentstore-backup")); - } - - int getSegmentCacheSize() { - return toInteger(getCacheSize(SEGMENT_CACHE_SIZE), DEFAULT_SEGMENT_CACHE_MB); - } - - int getStringCacheSize() { - return toInteger(getCacheSize(STRING_CACHE_SIZE), DEFAULT_STRING_CACHE_MB); - } - - int getTemplateCacheSize() { - return toInteger(getCacheSize(TEMPLATE_CACHE_SIZE), DEFAULT_TEMPLATE_CACHE_MB); - } - - int getStringDeduplicationCacheSize() { - return toInteger(getCacheSize(STRING_DEDUPLICATION_CACHE_SIZE), DEFAULT_STRING_CACHE_SIZE_OSGi); - } - - int getTemplateDeduplicationCacheSize() { - return toInteger(getCacheSize(TEMPLATE_DEDUPLICATION_CACHE_SIZE), DEFAULT_TEMPLATE_CACHE_SIZE_OSGi); - } - - int getNodeDeduplicationCacheSize() { - return roundToNextPowerOfTwo(toInteger(getCacheSize(NODE_DEDUPLICATION_CACHE_SIZE), DEFAULT_NODE_CACHE_SIZE_OSGi)); - } + @Override + public int getRetainedGenerations() { + return configuration.compaction_retainedGenerations(); + } - boolean getPauseCompaction() { - return toBoolean(property(PAUSE_COMPACTION), PAUSE_DEFAULT); - } + @Override + public int getDefaultRetainedGenerations() { + return RETAINED_GENERATIONS_DEFAULT; + } - int getRetryCount() { - return toInteger(property(COMPACTION_RETRY_COUNT), RETRY_COUNT_DEFAULT); - } + @Override + public boolean getPauseCompaction() { + return configuration.pauseCompaction(); + } - int getForceCompactionTimeout() { - return toInteger(property(COMPACTION_FORCE_TIMEOUT), FORCE_TIMEOUT_DEFAULT); - } + @Override + public int getRetryCount() { + return configuration.compaction_retryCount(); + } - int getRetainedGenerations() { - return toInteger(property(RETAINED_GENERATIONS), RETAINED_GENERATIONS_DEFAULT); - } + @Override + public int getForceCompactionTimeout() { + return configuration.compaction_force_timeout(); + } - long getSizeDeltaEstimation() { - return toLong(property(COMPACTION_SIZE_DELTA_ESTIMATION), SIZE_DELTA_ESTIMATION_DEFAULT); - } + @Override + public long getSizeDeltaEstimation() { + return configuration.compaction_sizeDeltaEstimation(); + } - int getMemoryThreshold() { - return toInteger(property(MEMORY_THRESHOLD), MEMORY_THRESHOLD_DEFAULT); - } + @Override + public int getMemoryThreshold() { + return configuration.compaction_memoryThreshold(); + } - boolean getDisableEstimation() { - return toBoolean(property(COMPACTION_DISABLE_ESTIMATION), DISABLE_ESTIMATION_DEFAULT); - } + @Override + public boolean getDisableEstimation() { + return configuration.compaction_disableEstimation(); + } - String getCompactionGainThreshold() { - return property("compaction.gainThreshold"); - } + @Override + public long getGCProcessLog() { + return configuration.compaction_progressLog(); + } - long getGCProcessLog() { - return toLong(property(GC_PROGRESS_LOG), GC_PROGRESS_LOG_DEFAULT); - } + @Override + public File getSegmentDirectory() { + return new File(getRepositoryHome(), "segmentstore"); + } - int getMaxFileSize() { - return toInteger(property(SIZE), DEFAULT_MAX_FILE_SIZE); - } + @Override + public int getSegmentCacheSize() { + Integer size = Integer.getInteger("segmentCache.size"); + if (size != null) { + return size; + } + return configuration.segmentCache_size(); + } - String getMode() { - String mode = property(MODE); - if (mode != null) { - return mode; - } - return System.getProperty(MODE, System.getProperty("sun.arch.data.model", "32")); - } + @Override + public int getStringCacheSize() { + return getCacheSize("stringCache.size", configuration.stringCache_size()); + } - boolean getMemoryMapping() { - return getMode().equals("64"); - } + @Override + public int getTemplateCacheSize() { + Integer size = Integer.getInteger("templateCache.size"); + if (size != null) { + return size; + } + return configuration.templateCache_size(); + } - long getBlobSnapshotInterval() { - return toLong(property(PROP_BLOB_SNAPSHOT_INTERVAL), DEFAULT_BLOB_SNAPSHOT_INTERVAL); - } + @Override + public int getStringDeduplicationCacheSize() { + Integer size = Integer.getInteger("stringDeduplicationCache.size"); + if (size != null) { + return size; + } + return configuration.stringDeduplicationCache_size(); + } - boolean isStandbyInstance() { - return toBoolean(property(STANDBY), false); - } + @Override + public int getTemplateDeduplicationCacheSize() { + Integer size = Integer.getInteger("templateDeduplicationCache.size"); + if (size != null) { + return size; + } + return configuration.templateDeduplicationCache_size(); + } - boolean hasCustomBlobStore() { - return toBoolean(property(CUSTOM_BLOB_STORE), false); - } + @Override + public int getNodeDeduplicationCacheSize() { + Integer size = Integer.getInteger("nodeDeduplicationCache.size"); + if (size != null) { + return roundToNextPowerOfTwo(size); + } + return roundToNextPowerOfTwo(configuration.nodeDeduplicationCache_size()); + } - boolean hasCustomSegmentStore() { - return toBoolean(property(CUSTOM_SEGMENT_STORE), false); - } + @Override + public int getMaxFileSize() { + return configuration.tarmk_size(); + } - long getBlobGcMaxAge() { - return toLong(property(PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE); - } + @Override + public boolean getMemoryMapping() { + return getMode().equals("64"); + } - boolean isPrimarySegmentStore() { - return role == null; - } + @Override + public boolean hasCustomBlobStore() { + return configuration.customBlobStore(); + } - private String appendRole(String name) { - if (role == null) { - return name; - } else { - return name + "-" + role; - } - } + @Override + public boolean hasCustomSegmentStore() { + return configuration.customSegmentStore(); + } - private String getCacheSize(String propertyName) { - String cacheSize = property(propertyName); - if (cacheSize != null) { - return cacheSize; - } - return System.getProperty(propertyName); - } + @Override + public boolean registerDescriptors() { + return true; + } -} + @Override + public String getRepositoryHome() { + return configuration.repository_home(); + } -/** - * Performs registrations of services and MBean in a uniform way. Augments - * the metadata of services and MBeans with an optionally provided role - * name. - */ -class Registrations { + @Override + public long getBlobSnapshotInterval() { + return configuration.blobTrackSnapshotIntervalInSecs(); + } - private final Whiteboard whiteboard; + @Override + public long getBlobGcMaxAge() { + return configuration.blobGcMaxAgeInSecs(); + } - private final String role; + @Override + public File getBackupDirectory() { + String backupDirectory = configuration.repository_backup_dir(); + if (isNullOrEmpty(backupDirectory)) { + return new File(getRepositoryHome(), "segmentstore-backup"); + } + return new File(backupDirectory); + } - Registrations(Whiteboard whiteboard, String role) { - this.whiteboard = whiteboard; - this.role = role; - } + @Override + public Whiteboard getWhiteboard() { + return whiteboard; + } - <T> Registration registerMBean(Class<T> clazz, T bean, String type, String name) { - return registerMBean(clazz, bean, type, name, new HashMap<String, String>()); - } + @Override + public Closer getCloser() { + return closer; + } - <T> Registration registerMBean(Class<T> clazz, T bean, String type, String name, Map<String, String> attributes) { - return WhiteboardUtils.registerMBean(whiteboard, clazz, bean, type, maybeAppendRole(name), maybePutRoleAttribute(attributes)); - } + @Override + public Logger getLogger() { + return logger; + } - <T> Registration register(Class<T> clazz, T service) { - return register(clazz, service, new HashMap<String, Object>()); - } + @Override + public StatisticsProvider getStatisticsProvider() { + return statisticsProvider; + } - <T> Registration register(Class<T> clazz, T service, Map<String, Object> properties) { - return whiteboard.register(clazz, service, maybePutRoleProperty(properties)); - } + @Override + public BlobStore getBlobStore() { + return blobStore; + } - private String maybeAppendRole(String name) { - return RoleUtils.maybeAppendRole(name, role); - } + @Override + public SegmentNodeStorePersistence getSegmentNodeStorePersistence() { + return segmentStore; + } - private String jmxRole() { - return role.replaceAll(":", "-"); - } + @Override + public BundleContext getBundleContext() { + return context.getBundleContext(); + } - private Map<String, String> maybePutRoleAttribute(Map<String, String> attributes) { - if (role != null) { - attributes.put("role", jmxRole()); - } - return attributes; + }); } - private Map<String, Object> maybePutRoleProperty(Map<String, Object> attributes) { - if (role != null) { - attributes.put("role", role); - } - return attributes; + @Deactivate + public void deactivate() { + closeQuietly(closer); } -} +} \ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java Fri Jul 13 13:23:24 2018 @@ -17,9 +17,9 @@ package org.apache.jackrabbit.oak.segment.osgi; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory; * detected problem and hinting at a possible solution. */ @Component( - policy = ConfigurationPolicy.REQUIRE, - configurationPid = "org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService" + configurationPolicy = ConfigurationPolicy.REQUIRE, + configurationPid = "org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService" ) public class SegmentNodeStoreServiceDeprecationError { Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java Fri Jul 13 13:23:24 2018 @@ -16,9 +16,9 @@ */ package org.apache.jackrabbit.oak.segment.osgi; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,8 +29,8 @@ import org.slf4j.LoggerFactory; * detected problem and hinting at a possible solution. */ @Component( - policy = ConfigurationPolicy.REQUIRE, - configurationPid = "org.apache.jackrabbit.oak.plugins.segment.standby.store.StandbyStoreService" + configurationPolicy = ConfigurationPolicy.REQUIRE, + configurationPid = "org.apache.jackrabbit.oak.plugins.segment.standby.store.StandbyStoreService" ) public class StandbyStoreServiceDeprecationError { Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java Fri Jul 13 13:23:24 2018 @@ -17,25 +17,15 @@ package org.apache.jackrabbit.oak.segment.standby.store; -import static java.lang.String.valueOf; -import static org.apache.felix.scr.annotations.ReferencePolicy.STATIC; -import static org.apache.felix.scr.annotations.ReferencePolicyOption.GREEDY; +import static org.osgi.service.component.annotations.ReferencePolicy.STATIC; +import static org.osgi.service.component.annotations.ReferencePolicyOption.GREEDY; -import java.io.Closeable; import java.io.File; import java.util.Dictionary; import java.util.Hashtable; import com.google.common.base.StandardSystemProperty; import com.google.common.io.Closer; -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.PropertyOption; -import org.apache.felix.scr.annotations.Reference; -import org.apache.jackrabbit.oak.commons.PropertiesUtil; import org.apache.jackrabbit.oak.segment.SegmentStore; import org.apache.jackrabbit.oak.segment.SegmentStoreProvider; import org.apache.jackrabbit.oak.segment.file.FileStore; @@ -43,71 +33,99 @@ import org.apache.jackrabbit.oak.segment import org.apache.jackrabbit.oak.segment.standby.server.StandbyServerSync; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@Property(name = "org.apache.sling.installer.configuration.persist", label = "Persist configuration", description = "Must be always disabled to avoid storing the configuration in the repository", boolValue = false) -@Component(metatype = true, policy = ConfigurationPolicy.REQUIRE) +@Component(configurationPolicy = ConfigurationPolicy.REQUIRE) +@Designate(ocd = StandbyStoreService.Configuration.class) public class StandbyStoreService { - private final Logger log = LoggerFactory.getLogger(getClass()); + private static final Logger log = LoggerFactory.getLogger(StandbyStoreService.class); - private static final String MODE_PRIMARY = "primary"; - - private static final String MODE_STANDBY = "standby"; - - public static final String MODE_DEFAULT = MODE_PRIMARY; - - @Property(options = { - @PropertyOption(name = MODE_PRIMARY, value = MODE_PRIMARY), - @PropertyOption(name = MODE_STANDBY, value = MODE_STANDBY)}, - value = MODE_DEFAULT) - public static final String MODE = "mode"; - - public static final int PORT_DEFAULT = 8023; - - @Property(intValue = PORT_DEFAULT) - public static final String PORT = "port"; - - public static final String PRIMARY_HOST_DEFAULT = "127.0.0.1"; - - @Property(value = PRIMARY_HOST_DEFAULT) - public static final String PRIMARY_HOST = "primary.host"; - - public static final int INTERVAL_DEFAULT = 5; - - @Property(intValue = INTERVAL_DEFAULT) - public static final String INTERVAL = "interval"; - - public static final String[] ALLOWED_CLIENT_IP_RANGES_DEFAULT = new String[] {}; - - @Property(cardinality = Integer.MAX_VALUE) - public static final String ALLOWED_CLIENT_IP_RANGES = "primary.allowed-client-ip-ranges"; - - public static final boolean SECURE_DEFAULT = false; - - @Property(boolValue = SECURE_DEFAULT) - public static final String SECURE = "secure"; - - public static final int READ_TIMEOUT_DEFAULT = 60000; - - @Property(intValue = READ_TIMEOUT_DEFAULT) - public static final String READ_TIMEOUT = "standby.readtimeout"; + private static final int BLOB_CHUNK_SIZE = Integer.getInteger("oak.standby.blob.chunkSize", 1024 * 1024); - public static final boolean AUTO_CLEAN_DEFAULT = true; + @ObjectClassDefinition( + name = "Apache Jackrabbit Oak Segment Tar Cold Standby Service", + description = "Provides continuous backups of repositories based on Segment Tar" + ) + @interface Configuration { + + @AttributeDefinition( + name = "Persist configuration", + description = "Must be always disabled to avoid storing the configuration in the repository" + ) + boolean org_apache_sling_installer_configuration_persist() default false; + + @AttributeDefinition( + name = "Mode", + description = "TarMK Cold Standby mode (primary or standby)", + options = { + @Option(label = "primary", value = "primary"), + @Option(label = "standby", value = "standby")} + ) + String mode() default "primary"; + + @AttributeDefinition( + name = "Port", + description = "TCP/IP port to use" + ) + int port() default 8023; + + @AttributeDefinition( + name = "Primary Host", + description = "Primary host (standby mode only)" + ) + String primary_host() default "127.0.0.1"; + + @AttributeDefinition( + name = "Sync interval (seconds)", + description = "Sync interval in seconds (standby mode only)" + ) + int interval() default 5; + + @AttributeDefinition( + name = "Allowed IP-Ranges", + description = "Accept incoming requests for these host names and IP-ranges only (primary mode only)", + cardinality = Integer.MAX_VALUE + ) + String[] primary_allowed$_$client$_$ip$_$ranges() default {}; + + @AttributeDefinition( + name = "Secure", + description = "Use secure connections" + ) + boolean secure() default false; + + @AttributeDefinition( + name = "Standby Read Timeout", + description = "Timeout for requests issued from the standby instance in milliseconds" + ) + int standby_readtimeout() default 60000; + + @AttributeDefinition( + name = "Standby Automatic Cleanup", + description = "Call the cleanup method when the root segment Garbage Collector (GC) generation number increases" + ) + boolean standby_autoclean() default true; - @Property(boolValue = AUTO_CLEAN_DEFAULT) - public static final String AUTO_CLEAN = "standby.autoclean"; + } @Reference(policy = STATIC, policyOption = GREEDY) private SegmentStoreProvider storeProvider = null; - - private static final int BLOB_CHUNK_SIZE = Integer.getInteger("oak.standby.blob.chunkSize", 1024 * 1024); private final Closer closer = Closer.create(); @Activate - private void activate(ComponentContext context) { + private void activate(ComponentContext context, Configuration config) { SegmentStore segmentStore = storeProvider.getSegmentStore(); if (!(segmentStore instanceof FileStore)) { @@ -116,15 +134,15 @@ public class StandbyStoreService { FileStore fileStore = (FileStore) segmentStore; - String mode = valueOf(context.getProperties().get(MODE)); + String mode = config.mode(); - if (MODE_PRIMARY.equals(mode)) { - bootstrapMaster(context, fileStore); + if (mode.equals("primary")) { + bootstrapMaster(config, fileStore); return; } - if (MODE_STANDBY.equals(mode)) { - bootstrapSlave(context, fileStore); + if (mode.equals("standby")) { + bootstrapSlave(context, config, fileStore); return; } @@ -136,11 +154,10 @@ public class StandbyStoreService { closer.close(); } - private void bootstrapMaster(ComponentContext context, FileStore fileStore) { - Dictionary<?, ?> props = context.getProperties(); - int port = PropertiesUtil.toInteger(props.get(PORT), PORT_DEFAULT); - String[] ranges = PropertiesUtil.toStringArray(props.get(ALLOWED_CLIENT_IP_RANGES), ALLOWED_CLIENT_IP_RANGES_DEFAULT); - boolean secure = PropertiesUtil.toBoolean(props.get(SECURE), SECURE_DEFAULT); + private void bootstrapMaster(Configuration config, FileStore fileStore) { + int port = config.port(); + String[] ranges = config.primary_allowed$_$client$_$ip$_$ranges(); + boolean secure = config.secure(); StandbyServerSync standbyServerSync = new StandbyServerSync(port, fileStore, BLOB_CHUNK_SIZE, ranges, secure); closer.register(standbyServerSync); @@ -149,14 +166,13 @@ public class StandbyStoreService { log.info("Started primary on port {} with allowed IP ranges {}", port, ranges); } - private void bootstrapSlave(ComponentContext context, FileStore fileStore) { - Dictionary<?, ?> props = context.getProperties(); - int port = PropertiesUtil.toInteger(props.get(PORT), PORT_DEFAULT); - long interval = PropertiesUtil.toInteger(props.get(INTERVAL), INTERVAL_DEFAULT); - String host = PropertiesUtil.toString(props.get(PRIMARY_HOST), PRIMARY_HOST_DEFAULT); - boolean secure = PropertiesUtil.toBoolean(props.get(SECURE), SECURE_DEFAULT); - int readTimeout = PropertiesUtil.toInteger(props.get(READ_TIMEOUT), READ_TIMEOUT_DEFAULT); - boolean clean = PropertiesUtil.toBoolean(props.get(AUTO_CLEAN), AUTO_CLEAN_DEFAULT); + private void bootstrapSlave(ComponentContext context, Configuration config, FileStore fileStore) { + int port = config.port(); + long interval = config.interval(); + String host = config.primary_host(); + boolean secure = config.secure(); + int readTimeout = config.standby_readtimeout(); + boolean clean = config.standby_autoclean(); StandbyClientSync standbyClientSync = new StandbyClientSync(host, port, fileStore, secure, readTimeout, clean, new File(StandardSystemProperty.JAVA_IO_TMPDIR.value())); closer.register(standbyClientSync); @@ -165,20 +181,9 @@ public class StandbyStoreService { dictionary.put("scheduler.period", interval); dictionary.put("scheduler.concurrent", false); ServiceRegistration registration = context.getBundleContext().registerService(Runnable.class.getName(), standbyClientSync, dictionary); - closer.register(asCloseable(registration)); + closer.register(registration::unregister); log.info("Started standby on port {} with {}s sync frequency", port, interval); } - private static Closeable asCloseable(final ServiceRegistration r) { - return new Closeable() { - - @Override - public void close() { - r.unregister(); - } - - }; - } - } Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java Fri Jul 13 13:23:24 2018 @@ -35,9 +35,9 @@ public class SegmentNodeStoreFactoryTest protected void registerSegmentNodeStoreService(boolean customBlobStore) { Map<String, Object> properties = newHashMap(); - properties.put(SegmentNodeStoreFactory.ROLE, "some-role"); - properties.put(SegmentNodeStoreFactory.CUSTOM_BLOB_STORE, customBlobStore); - properties.put(SegmentNodeStoreService.REPOSITORY_HOME_DIRECTORY, folder.getRoot().getAbsolutePath()); + properties.put("role", "some-role"); + properties.put("customBlobStore", customBlobStore); + properties.put("repository.home", folder.getRoot().getAbsolutePath()); segmentNodeStoreFactory = context.registerInjectActivateService(new SegmentNodeStoreFactory(), properties); } Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java Fri Jul 13 13:23:24 2018 @@ -21,6 +21,7 @@ package org.apache.jackrabbit.oak.segmen import java.io.InputStream; +import javax.print.attribute.HashPrintServiceAttributeSet; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -47,6 +48,10 @@ class ComponentDescriptor { return element.hasAttribute(name) && element.getAttribute(name).equals(value); } + private static boolean hasNoAttribute(Element element, String name) { + return !element.hasAttribute(name); + } + boolean hasName(String name) { return hasAttribute(root, "name", name); } @@ -182,6 +187,8 @@ class ComponentDescriptor { private String unbind; + private String field; + private HasReference(String name) { this.name = name; } @@ -246,6 +253,11 @@ class ComponentDescriptor { return this; } + HasReference withField(String field) { + this.field = field; + return this; + } + boolean check() { NodeList references = root.getElementsByTagName("reference"); for (int i = 0; i < references.getLength(); i++) { @@ -254,10 +266,10 @@ class ComponentDescriptor { if (iface != null && !hasAttribute(reference, "interface", iface)) { return false; } - if (cardinality != null && !hasAttribute(reference, "cardinality", cardinality)) { + if (cardinality != null && !hasValidCardinality(reference)) { return false; } - if (policy != null && !hasAttribute(reference, "policy", policy)) { + if (policy != null && !hasValidPolicy(reference)) { return false; } if (policyOption != null && !hasAttribute(reference, "policy-option", policyOption)) { @@ -272,12 +284,29 @@ class ComponentDescriptor { if (unbind != null && !hasAttribute(reference, "unbind", unbind)) { return false; } + if (field != null && !hasAttribute(reference, "field", field)) { + return false; + } return true; } } return false; } + private boolean hasValidCardinality(Element reference) { + if (cardinality.equals("1..1") && hasNoAttribute(reference, "cardinality")) { + return true; + } + return hasAttribute(reference, "cardinality", cardinality); + } + + private boolean hasValidPolicy(Element reference) { + if (policy.equals("static") && hasNoAttribute(reference, "policy")) { + return true; + } + return hasAttribute(reference, "policy", policy); + } + } HasReference hasReference(String name) { Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java Fri Jul 13 13:23:24 2018 @@ -52,36 +52,32 @@ public class SegmentNodeStoreFactoryTest .withStaticPolicy() .withGreedyPolicyOption() .withTarget("(&(!(split.blobstore=old))(!(split.blobstore=new)))") - .withBind("bindBlobStore") - .withUnbind("unbindBlobStore") + .withField("blobStore") .check()); assertTrue(cd.hasReference("segmentStore") .withInterface("org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence") .withOptionalUnaryCardinality() .withStaticPolicy() .withGreedyPolicyOption() - .withBind("bindSegmentStore") - .withUnbind("unbindSegmentStore") + .withField("segmentStore") .check()); assertTrue(cd.hasReference("statisticsProvider") .withInterface("org.apache.jackrabbit.oak.stats.StatisticsProvider") .withMandatoryUnaryCardinality() .withStaticPolicy() - .withBind("bindStatisticsProvider") - .withUnbind("unbindStatisticsProvider") + .withField("statisticsProvider") .check()); } @Test public void testMetatypeInformation() throws Exception { - MetatypeInformation mi = MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory.xml")); + MetatypeInformation mi = MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory$Configuration.xml")); assertTrue(mi.hasDesignate() - .withPid("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory") .withFactoryPid("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory") - .withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory") + .withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory$Configuration") .check()); - ObjectClassDefinition ocd = mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory"); + ObjectClassDefinition ocd = mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory$Configuration"); assertTrue(ocd.hasAttributeDefinition("role") .withStringType() .check()); Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java?rev=1835837&r1=1835836&r2=1835837&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java (original) +++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java Fri Jul 13 13:23:24 2018 @@ -33,25 +33,23 @@ public class SegmentNodeStoreMonitorServ assertTrue(cd.hasRequireConfigurationPolicy()); assertTrue(cd.hasActivateMethod("activate")); assertTrue(cd.hasImplementationClass("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService")); - assertTrue(cd.hasProperty("commitsTrackerWriterGroups").check()); assertTrue(cd.hasReference("snsStatsMBean") .withInterface("org.apache.jackrabbit.oak.segment.SegmentNodeStoreStatsMBean") .withMandatoryUnaryCardinality() .withStaticPolicy() - .withBind("bindSnsStatsMBean") - .withUnbind("unbindSnsStatsMBean") + .withField("snsStatsMBean") .check()); } @Test public void testMetatypeInformation() throws Exception { - MetatypeInformation mi = MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService.xml")); + MetatypeInformation mi = MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService$Configuration.xml")); assertTrue(mi.hasDesignate() .withPid("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService") - .withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService") + .withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService$Configuration") .check()); - ObjectClassDefinition ocd = mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService"); + ObjectClassDefinition ocd = mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService$Configuration"); assertTrue(ocd.hasAttributeDefinition("commitsTrackerWriterGroups") .withStringType() .withCardinality("2147483647")
