/*
* 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.activemq.artemis.core.paging.impl;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.io.IOCriticalErrorListener;
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
import org.apache.activemq.artemis.core.paging.PagingManager;
import org.apache.activemq.artemis.core.paging.PagingStore;
import org.apache.activemq.artemis.core.paging.PagingStoreFactory;
import org.apache.activemq.artemis.core.paging.cursor.PageCursorProvider;
import org.apache.activemq.artemis.core.paging.cursor.impl.PageCursorProviderImpl;
import org.apache.activemq.artemis.core.persistence.StorageManager;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.files.FileMoveManager;
import org.apache.activemq.artemis.core.server.files.FileStoreMonitor;
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.utils.ExecutorFactory;
import org.apache.activemq.artemis.utils.UUIDGenerator;
/**
* Integration point between Paging and NIO
*/
public class PagingStoreFactoryNIO implements PagingStoreFactory {
// Constants -----------------------------------------------------
private static final String ADDRESS_FILE = "address.txt";
// Attributes ----------------------------------------------------
private final File directory;
private final ExecutorFactory executorFactory;
protected final boolean syncNonTransactional;
private PagingManager pagingManager;
private final ScheduledExecutorService scheduledExecutor;
private final long syncTimeout;
protected final StorageManager storageManager;
private final IOCriticalErrorListener critialErrorListener;
public PagingStoreFactoryNIO(final StorageManager storageManager,
final File directory,
final long syncTimeout,
final ScheduledExecutorService scheduledExecutor,
final ExecutorFactory executorFactory,
final boolean syncNonTransactional,
final IOCriticalErrorListener critialErrorListener) {
this.storageManager = storageManager;
this.directory = directory;
this.executorFactory = executorFactory;
this.syncNonTransactional = syncNonTransactional;
this.scheduledExecutor = scheduledExecutor;
this.syncTimeout = syncTimeout;
this.critialErrorListener = critialErrorListener;
}
// Public --------------------------------------------------------
@Override
public ScheduledExecutorService getScheduledExecutor() {
return scheduledExecutor;
}
@Override
public Executor newExecutor() {
return executorFactory.getExecutor();
}
@Override
public void stop() {
}
@Override
public void injectMonitor(FileStoreMonitor monitor) throws Exception {
monitor.addStore(this.directory);
}
@Override
public PageCursorProvider newCursorProvider(PagingStore store,
StorageManager storageManager,
AddressSettings addressSettings,
Executor executor) {
return new PageCursorProviderImpl(store, storageManager, executor, addressSettings.getPageCacheMaxSize());
}
@Override
public synchronized PagingStore newStore(final SimpleString address, final AddressSettings settings) {
return new PagingStoreImpl(address, scheduledExecutor, syncTimeout, pagingManager, storageManager, null, this, address, settings, executorFactory.getExecutor(), syncNonTransactional);
}
@Override
public synchronized SequentialFileFactory newFileFactory(final SimpleString address) throws Exception {
String guid = UUIDGenerator.getInstance().generateStringUUID();
SequentialFileFactory factory = newFileFactory(guid);
factory.createDirs();
File fileWithID = new File(directory, guid +
File.separatorChar +
PagingStoreFactoryNIO.ADDRESS_FILE);
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileWithID)))) {
writer.write(address.toString());
writer.newLine();
}
return factory;
}
@Override
public void setPagingManager(final PagingManager pagingManager) {
this.pagingManager = pagingManager;
}
@Override
public List<PagingStore> reloadStores(final HierarchicalRepository<AddressSettings> addressSettingsRepository) throws Exception {
File[] files = directory.listFiles();
if (files == null) {
return Collections.<PagingStore>emptyList();
} else {
ArrayList<PagingStore> storesReturn = new ArrayList<>(files.length);
for (File file : files) {
final String guid = file.getName();
final File addressFile = new File(file, PagingStoreFactoryNIO.ADDRESS_FILE);
if (!addressFile.exists()) {
// This means this folder is from a replication copy, nothing to worry about it, we just skip it
if (!file.getName().contains(FileMoveManager.PREFIX)) {
ActiveMQServerLogger.LOGGER.pageStoreFactoryNoIdFile(file.toString(), PagingStoreFactoryNIO.ADDRESS_FILE);
}
continue;
}
String addressString;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(addressFile)))) {
addressString = reader.readLine();
}
SimpleString address = new SimpleString(addressString);
SequentialFileFactory factory = newFileFactory(guid);
AddressSettings settings = addressSettingsRepository.getMatch(address.toString());
PagingStore store = new PagingStoreImpl(address, scheduledExecutor, syncTimeout, pagingManager, storageManager, factory, this, address, settings, executorFactory.getExecutor(), syncNonTransactional);
storesReturn.add(store);
}
return storesReturn;
}
}
private SequentialFileFactory newFileFactory(final String directoryName) {
return new NIOSequentialFileFactory(new File(directory, directoryName), false, critialErrorListener, 1);
}
}