public Backend(Configuration storageConfig) { this.storageConfig = storageConfig; storeManager = getStorageManager(storageConfig); indexes = getIndexes(storageConfig); storeFeatures = storeManager.getFeatures(); basicMetrics = storageConfig.getBoolean(BASIC_METRICS, BASIC_METRICS_DEFAULT); mergeBasicMetrics = storageConfig.getBoolean(MERGE_BASIC_METRICS_KEY, MERGE_BASIC_METRICS_DEFAULT); int bufferSizeTmp = storageConfig.getInt(BUFFER_SIZE_KEY, BUFFER_SIZE_DEFAULT); Preconditions.checkArgument( bufferSizeTmp >= 0, "Buffer size must be non-negative (use 0 to disable)"); if (!storeFeatures.supportsBatchMutation()) { bufferSize = 0; log.debug("Buffering disabled because backend does not support batch mutations"); } else bufferSize = bufferSizeTmp; writeAttempts = storageConfig.getInt(WRITE_ATTEMPTS_KEY, WRITE_ATTEMPTS_DEFAULT); Preconditions.checkArgument(writeAttempts > 0, "Write attempts must be positive"); readAttempts = storageConfig.getInt(READ_ATTEMPTS_KEY, READ_ATTEMPTS_DEFAULT); Preconditions.checkArgument(readAttempts > 0, "Read attempts must be positive"); persistAttemptWaittime = storageConfig.getInt(STORAGE_ATTEMPT_WAITTIME_KEY, STORAGE_ATTEMPT_WAITTIME_DEFAULT); Preconditions.checkArgument( persistAttemptWaittime > 0, "Persistence attempt retry wait time must be non-negative"); // If lock prefix is unspecified, specify it now storageConfig.setProperty( ExpectedValueCheckingStore.LOCAL_LOCK_MEDIATOR_PREFIX_KEY, storageConfig.getString( ExpectedValueCheckingStore.LOCAL_LOCK_MEDIATOR_PREFIX_KEY, storeManager.getName())); final String lockBackendName = storageConfig.getString( GraphDatabaseConfiguration.LOCK_BACKEND, GraphDatabaseConfiguration.LOCK_BACKEND_DEFAULT); if (REGISTERED_LOCKERS.containsKey(lockBackendName)) { lockerCreator = REGISTERED_LOCKERS.get(lockBackendName); } else { throw new TitanConfigurationException( "Unknown lock backend \"" + lockBackendName + "\". Known lock backends: " + Joiner.on(", ").join(REGISTERED_LOCKERS.keySet()) + "."); } // Never used for backends that have innate transaction support, but we // want to maintain the non-null invariant regardless; it will default // to connsistentkey impl if none is specified Preconditions.checkNotNull(lockerCreator); if (storeFeatures.isDistributed() && storeFeatures.isKeyOrdered()) { log.debug("Wrapping index store with HashPrefix"); hashPrefixIndex = true; } else { hashPrefixIndex = false; } }
private Log openLog(String logManagerName, String logName) { try { ModifiableConfiguration configuration = new ModifiableConfiguration( GraphDatabaseConfiguration.ROOT_NS, config.copy(), BasicConfiguration.Restriction.NONE); configuration.set(GraphDatabaseConfiguration.UNIQUE_INSTANCE_ID, "reader"); configuration.set( GraphDatabaseConfiguration.LOG_READ_INTERVAL, Duration.ofMillis(500L), logManagerName); if (logStoreManager == null) { logStoreManager = Backend.getStorageManager(configuration); } StoreFeatures f = logStoreManager.getFeatures(); boolean part = f.isDistributed() && f.isKeyOrdered(); if (part) { for (String logname : new String[] {USER_LOG, TRANSACTION_LOG, MANAGEMENT_LOG}) configuration.set(KCVSLogManager.LOG_MAX_PARTITIONS, 8, logname); } assert logStoreManager != null; if (!logManagers.containsKey(logManagerName)) { // Open log manager - only supports KCVSLog Configuration logConfig = configuration.restrictTo(logManagerName); Preconditions.checkArgument( logConfig.get(LOG_BACKEND).equals(LOG_BACKEND.getDefaultValue())); logManagers.put(logManagerName, new KCVSLogManager(logStoreManager, logConfig)); } assert logManagers.containsKey(logManagerName); return logManagers.get(logManagerName).openLog(logName); } catch (BackendException e) { throw new TitanException("Could not open log: " + logName, e); } }
public BackendTransaction beginTransaction() throws StorageException { StoreTransaction tx = storeManager.beginTransaction(ConsistencyLevel.DEFAULT); if (bufferSize > 1) { assert storeManager.getFeatures().supportsBatchMutation(); if (isKeyColumnValueStore) { assert storeManager instanceof KeyColumnValueStoreManager; tx = new BufferTransaction( tx, (KeyColumnValueStoreManager) storeManager, bufferSize, writeAttempts, persistAttemptWaittime); } else { assert storeManager instanceof KeyValueStoreManager; // TODO: support buffer mutations } } if (!storeFeatures.supportsLocking()) { if (storeFeatures.isTransactional()) { // No transaction wrapping needed } else if (storeFeatures.supportsConsistentKeyOperations()) { tx = new ConsistentKeyLockTransaction( tx, storeManager.beginTransaction(ConsistencyLevel.KEY_CONSISTENT)); } } return new BackendTransaction(tx); }
private KeyColumnValueStore getLockStore(KeyColumnValueStore store) throws StorageException { if (!storeFeatures.supportsLocking()) { if (storeFeatures.isTransactional()) { store = new TransactionalLockStore(store); } else if (storeFeatures.supportsConsistentKeyOperations()) { store = new ConsistentKeyLockStore( store, getStore(store.getName() + LOCK_STORE_SUFFIX), lockConfiguration); } else throw new IllegalArgumentException("Store needs to support some form of locking"); } return store; }
public EntryMetaData[] getMetaDataSchema(String storeName) { List<EntryMetaData> schemaBuilder = Lists.newArrayList(); StoreFeatures features = getFeatures(); if (features.hasTimestamps() && storageConfig.get(STORE_META_TIMESTAMPS, storeName)) schemaBuilder.add(EntryMetaData.TIMESTAMP); if (features.hasCellTTL() && storageConfig.get(STORE_META_TTL, storeName)) schemaBuilder.add(EntryMetaData.TTL); if (features.hasVisibility() && storageConfig.get(STORE_META_VISIBILITY, storeName)) schemaBuilder.add(EntryMetaData.VISIBILITY); if (schemaBuilder.isEmpty()) return StaticArrayEntry.EMPTY_SCHEMA; return schemaBuilder.toArray(new EntryMetaData[schemaBuilder.size()]); }
private KeyColumnValueStore getLockStore(KeyColumnValueStore store, boolean lockEnabled) throws StorageException { if (!storeFeatures.supportsLocking()) { if (storeFeatures.supportsTransactions()) { store = new TransactionalLockStore(store); } else if (storeFeatures.supportsConsistentKeyOperations()) { if (lockEnabled) { final String lockerName = store.getName() + LOCK_STORE_SUFFIX; store = new ExpectedValueCheckingStore(store, getLocker(lockerName)); } else { store = new ExpectedValueCheckingStore(store, null); } } else throw new IllegalArgumentException("Store needs to support some form of locking"); } return store; }
public KeyValueStoreManagerAdapter( KeyValueStoreManager manager, Map<String, Integer> keyLengths) { this.manager = manager; ImmutableMap.Builder<String, Integer> mb = ImmutableMap.builder(); if (keyLengths != null && !keyLengths.isEmpty()) mb.putAll(keyLengths); this.keyLengths = mb.build(); features = manager.getFeatures().clone(); features.supportsBatchMutation = false; }
/** * Opens a new transaction against all registered backend system wrapped in one {@link * BackendTransaction}. * * @return * @throws StorageException */ public BackendTransaction beginTransaction(TransactionConfiguration configuration) throws StorageException { StoreTxConfig txConfig = new StoreTxConfig(configuration.getMetricsPrefix()); if (configuration.hasTimestamp()) txConfig.setTimestamp(configuration.getTimestamp()); StoreTransaction tx = storeManager.beginTransaction(txConfig); if (bufferSize > 1) { Preconditions.checkArgument(storeManager.getFeatures().supportsBatchMutation()); tx = new BufferTransaction( tx, storeManager, bufferSize, writeAttempts, persistAttemptWaittime); } if (!storeFeatures.supportsLocking()) { if (storeFeatures.supportsTransactions()) { // No transaction wrapping needed } else if (storeFeatures.supportsConsistentKeyOperations()) { txConfig = new StoreTxConfig(ConsistencyLevel.KEY_CONSISTENT, configuration.getMetricsPrefix()); if (configuration.hasTimestamp()) txConfig.setTimestamp(configuration.getTimestamp()); tx = new ExpectedValueCheckingTransaction( tx, storeManager.beginTransaction(txConfig), readAttempts); } } // Index transactions Map<String, IndexTransaction> indexTx = new HashMap<String, IndexTransaction>(indexes.size()); for (Map.Entry<String, IndexProvider> entry : indexes.entrySet()) { indexTx.put(entry.getKey(), new IndexTransaction(entry.getValue())); } return new BackendTransaction( tx, storeManager.getFeatures(), edgeStore, vertexIndexStore, edgeIndexStore, readAttempts, persistAttemptWaittime, indexTx); }
public void initialize(Configuration config) { try { // EdgeStore & VertexIndexStore KeyColumnValueStore idStore = getStore(ID_STORE_NAME); idAuthority = null; if (storeFeatures.isTransactional()) { idAuthority = new TransactionalIDManager(idStore, storeManager, config); } else if (storeFeatures.supportsConsistentKeyOperations()) { idAuthority = new ConsistentKeyIDManager(idStore, storeManager, config); } else { idAuthority = new TransactionalIDManager(idStore, storeManager, config); log.error( "Store needs to support consistent key or transactional operations for ID manager to guarantee proper id allocations"); } edgeStore = getLockStore(getBufferStore(EDGESTORE_NAME)); vertexIndexStore = getLockStore(getBufferStore(VERTEXINDEX_STORE_NAME)); if (hashPrefixIndex) vertexIndexStore = new HashPrefixKeyColumnValueStore(vertexIndexStore, 4); } catch (StorageException e) { throw new TitanException("Could not initialize backend", e); } }
public HBaseStoreManager(org.apache.commons.configuration.Configuration config) throws StorageException { super(config, PORT_DEFAULT); this.tableName = config.getString(TABLE_NAME_KEY, TABLE_NAME_DEFAULT); this.hconf = HBaseConfiguration.create(); for (Map.Entry<String, String> confEntry : HBASE_CONFIGURATION.entrySet()) { if (config.containsKey(confEntry.getKey())) { hconf.set(confEntry.getValue(), config.getString(confEntry.getKey())); } } // Copy a subset of our commons config into a Hadoop config org.apache.commons.configuration.Configuration hbCommons = config.subset(HBASE_CONFIGURATION_NAMESPACE); @SuppressWarnings("unchecked") // I hope commons-config eventually fixes this Iterator<String> keys = hbCommons.getKeys(); int keysLoaded = 0; while (keys.hasNext()) { String key = keys.next(); String value = hbCommons.getString(key); logger.debug("HBase configuration: setting {}={}", key, value); hconf.set(key, value); keysLoaded++; } logger.debug("HBase configuration: set a total of {} configuration values", keysLoaded); connectionPool = new HTablePool(hconf, connectionPoolSize); openStores = new ConcurrentHashMap<String, HBaseKeyColumnValueStore>(); // TODO: allowing publicly mutate fields is bad, should be fixed features = new StoreFeatures(); features.supportsScan = true; features.supportsBatchMutation = true; features.supportsTransactions = false; features.supportsConsistentKeyOperations = true; features.supportsLocking = false; features.isKeyOrdered = false; features.isDistributed = true; features.hasLocalKeyPartition = false; }
public Backend(Configuration storageConfig) { storeManager = getStorageManager(storageConfig); isKeyColumnValueStore = storeManager instanceof KeyColumnValueStoreManager; storeFeatures = storeManager.getFeatures(); int bufferSizeTmp = storageConfig.getInt(BUFFER_SIZE_KEY, BUFFER_SIZE_DEFAULT); Preconditions.checkArgument( bufferSizeTmp >= 0, "Buffer size must be non-negative (use 0 to disable)"); if (!storeFeatures.supportsBatchMutation()) { bufferSize = 0; log.debug("Buffering disabled because backend does not support batch mutations"); } else bufferSize = bufferSizeTmp; if (!storeFeatures.supportsLocking() && storeFeatures.supportsConsistentKeyOperations()) { lockConfiguration = new ConsistentKeyLockConfiguration(storageConfig, storeManager.toString()); } else { lockConfiguration = null; } writeAttempts = storageConfig.getInt(WRITE_ATTEMPTS_KEY, WRITE_ATTEMPTS_DEFAULT); Preconditions.checkArgument(writeAttempts > 0, "Write attempts must be positive"); readAttempts = storageConfig.getInt(READ_ATTEMPTS_KEY, READ_ATTEMPTS_DEFAULT); Preconditions.checkArgument(readAttempts > 0, "Read attempts must be positive"); persistAttemptWaittime = storageConfig.getInt(STORAGE_ATTEMPT_WAITTIME_KEY, STORAGE_ATTEMPT_WAITTIME_DEFAULT); Preconditions.checkArgument( persistAttemptWaittime > 0, "Persistence attempt retry wait time must be non-negative"); if (storeFeatures.isDistributed() && storeFeatures.isKeyOrdered()) { log.debug("Wrapping index store with HashPrefix"); hashPrefixIndex = true; } else { hashPrefixIndex = false; } }
public static boolean supportsStoreTTL(StoreFeatures features) { return features.hasCellTTL() || features.hasStoreTTL(); }
@Test public void testFeaturesImplementation() { StoreFeatures features; features = new StandardStoreFeatures.Builder().build(); assertFalse(features.hasMultiQuery()); assertFalse(features.hasLocking()); assertFalse(features.isDistributed()); assertFalse(features.hasScan()); features = new StandardStoreFeatures.Builder().locking(true).build(); assertFalse(features.hasMultiQuery()); assertTrue(features.hasLocking()); assertFalse(features.isDistributed()); features = new StandardStoreFeatures.Builder().multiQuery(true).unorderedScan(true).build(); assertTrue(features.hasMultiQuery()); assertTrue(features.hasUnorderedScan()); assertFalse(features.hasOrderedScan()); assertTrue(features.hasScan()); assertFalse(features.isDistributed()); assertFalse(features.hasLocking()); }
/** * Initializes this backend with the given configuration. Must be called before this Backend can * be used * * @param config */ public void initialize(Configuration config) { try { // EdgeStore & VertexIndexStore KeyColumnValueStore idStore = getStore(ID_STORE_NAME); if (basicMetrics) { idStore = new MetricInstrumentedStore(idStore, getMetricsStoreName("idStore")); } idAuthority = null; if (storeFeatures.supportsTransactions()) { idAuthority = new TransactionalIDManager(idStore, storeManager, config); } else if (storeFeatures.supportsConsistentKeyOperations()) { idAuthority = new ConsistentKeyIDManager(idStore, storeManager, config); } else { throw new IllegalStateException( "Store needs to support consistent key or transactional operations for ID manager to guarantee proper id allocations"); } edgeStore = getLockStore(getBufferStore(EDGESTORE_NAME)); vertexIndexStore = getLockStore(getBufferStore(VERTEXINDEX_STORE_NAME)); edgeIndexStore = getLockStore(getBufferStore(EDGEINDEX_STORE_NAME), false); if (hashPrefixIndex) { vertexIndexStore = new HashPrefixKeyColumnValueStore(vertexIndexStore, 4); edgeIndexStore = new HashPrefixKeyColumnValueStore(edgeIndexStore, 4); } if (basicMetrics) { edgeStore = new MetricInstrumentedStore(edgeStore, getMetricsStoreName("edgeStore")); vertexIndexStore = new MetricInstrumentedStore(vertexIndexStore, getMetricsStoreName("vertexIndexStore")); edgeIndexStore = new MetricInstrumentedStore(edgeIndexStore, getMetricsStoreName("edgeIndexStore")); } String version = BackendOperation.execute( new Callable<String>() { @Override public String call() throws Exception { String version = storeManager.getConfigurationProperty(TITAN_BACKEND_VERSION); if (version == null) { storeManager.setConfigurationProperty( TITAN_BACKEND_VERSION, TitanConstants.VERSION); version = TitanConstants.VERSION; } return version; } @Override public String toString() { return "ConfigurationRead"; } }, config.getLong(SETUP_WAITTIME_KEY, SETUP_WAITTIME_DEFAULT)); Preconditions.checkState(version != null, "Could not read version from storage backend"); if (!TitanConstants.VERSION.equals(version) && !TitanConstants.COMPATIBLE_VERSIONS.contains(version)) { throw new TitanException( "StorageBackend version is incompatible with current Titan version: " + version + " vs. " + TitanConstants.VERSION); } } catch (StorageException e) { throw new TitanException("Could not initialize backend", e); } }