Fixed implementation for HawtDB storage of subscriptions
This commit is contained in:
@@ -27,4 +27,6 @@ public interface IMessaging {
|
||||
* was subscribed
|
||||
*/
|
||||
void removeSubscriptions(String clientID);
|
||||
|
||||
void close();
|
||||
}
|
||||
|
||||
@@ -58,4 +58,10 @@ public class SimpleMessaging implements IMessaging {
|
||||
subscriptions.removeForClient(clientID);
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
rwLock.writeLock().lock();
|
||||
subscriptions.close();
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dna.mqtt.moquette.messaging.spi.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
|
||||
|
||||
/**
|
||||
@@ -9,7 +10,7 @@ import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class Subscription {
|
||||
public class Subscription implements Serializable {
|
||||
|
||||
QOSType requestedQos;
|
||||
String clientId;
|
||||
|
||||
+31
-15
@@ -9,8 +9,10 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
import org.dna.mqtt.moquette.MQTTException;
|
||||
import org.dna.mqtt.moquette.server.MQTTHandler;
|
||||
import org.dna.mqtt.moquette.server.Server;
|
||||
import org.fusesource.hawtbuf.codec.StringCodec;
|
||||
import org.fusesource.hawtdb.api.BTreeIndexFactory;
|
||||
import org.fusesource.hawtdb.api.PageFile;
|
||||
@@ -197,41 +199,46 @@ public class SubscriptionsStore {
|
||||
}
|
||||
// private List<Subscription> subscriptions = new ArrayList<Subscription>();
|
||||
private TreeNode subscriptions = new TreeNode(null);
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionsStore.class);
|
||||
|
||||
//pesistent Map of clientID, list of Subscriptions
|
||||
private SortedIndex<String, List<Subscription>> m_persistent;
|
||||
private PageFile pageFile;
|
||||
// private PageFile pageFile;
|
||||
private PageFileFactory factory;
|
||||
|
||||
/**
|
||||
* Initialize basic store structures, like the FS storage to maintain
|
||||
* client's topics subscriptions
|
||||
*/
|
||||
public void init() {
|
||||
PageFileFactory factory = new PageFileFactory();
|
||||
/*StringBuilder storeFile = new StringBuilder();
|
||||
storeFile.append(System.getProperty("user.home"))
|
||||
.append(File.separator).append("moquette_store.hawtdb");*/
|
||||
String storeFile = Server.STORAGE_FILE_PATH;
|
||||
|
||||
factory = new PageFileFactory();
|
||||
File tmpFile;
|
||||
try {
|
||||
tmpFile = File.createTempFile("hawtdb", "test");
|
||||
tmpFile = new File(storeFile.toString());
|
||||
tmpFile.createNewFile();
|
||||
} catch (IOException ex) {
|
||||
LOG.error(null, ex);
|
||||
throw new MQTTException("Can't create temp file for subscriptions storage", ex);
|
||||
throw new MQTTException("Can't create temp file for subscriptions storage [" + storeFile + "]", ex);
|
||||
}
|
||||
factory.setFile(/*new File("mydb.dat")*/tmpFile);
|
||||
factory.open();
|
||||
pageFile = factory.getPageFile();
|
||||
PageFile pageFile = factory.getPageFile();
|
||||
|
||||
// HashIndexFactory<String, List<Subscription>> indexFactory =
|
||||
// new HashIndexFactory<String, List<Subscription>>();
|
||||
BTreeIndexFactory<String, List<Subscription>> indexFactory =
|
||||
BTreeIndexFactory<String, List<Subscription>> indexFactory =
|
||||
new BTreeIndexFactory<String, List<Subscription>>();
|
||||
indexFactory.setKeyCodec(StringCodec.INSTANCE);
|
||||
|
||||
|
||||
m_persistent = indexFactory.openOrCreate(pageFile);
|
||||
|
||||
|
||||
//reaload any subscriptions persisted
|
||||
LOG.debug("Reloading all stored subscriptions...");
|
||||
for(Map.Entry<String, List<Subscription>> entry: m_persistent) {
|
||||
for (Map.Entry<String, List<Subscription>> entry : m_persistent) {
|
||||
for (Subscription subscription : entry.getValue()) {
|
||||
addDirect(subscription);
|
||||
}
|
||||
@@ -239,7 +246,15 @@ public class SubscriptionsStore {
|
||||
LOG.debug("Finished loading");
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
factory.close();
|
||||
} catch (IOException ex) {
|
||||
//TODO handle probably firing
|
||||
LOG.error(null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDirect(Subscription newSubscription) {
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
try {
|
||||
@@ -275,10 +290,11 @@ public class SubscriptionsStore {
|
||||
if (!m_persistent.containsKey(clientID)) {
|
||||
m_persistent.put(clientID, new ArrayList<Subscription>());
|
||||
}
|
||||
|
||||
|
||||
List<Subscription> subs = m_persistent.get(clientID);
|
||||
subs.add(newSubscription);
|
||||
pageFile.flush();
|
||||
m_persistent.put(clientID, subs);
|
||||
// pageFile.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +302,7 @@ public class SubscriptionsStore {
|
||||
*/
|
||||
public void removeForClient(String clientID) {
|
||||
subscriptions.removeClientSubscriptions(clientID);
|
||||
|
||||
|
||||
//remove from log all subscriptions
|
||||
m_persistent.remove(clientID);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dna.mqtt.moquette.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.apache.mina.core.service.IoAcceptor;
|
||||
@@ -36,7 +37,10 @@ public class Server {
|
||||
|
||||
public static final int PORT = 9191;
|
||||
public static final int DEFAULT_CONNECT_TIMEOUT = 10;
|
||||
public static final String STORAGE_FILE_PATH = System.getProperty("user.home") +
|
||||
File.separator + "moquette_store.hawtdb";
|
||||
private IoAcceptor m_acceptor;
|
||||
SimpleMessaging messaging;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new Server().startServer();
|
||||
@@ -64,7 +68,7 @@ public class Server {
|
||||
m_acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(encoder, decoder));
|
||||
|
||||
MQTTHandler handler = new MQTTHandler();
|
||||
SimpleMessaging messaging = new SimpleMessaging();
|
||||
messaging = new SimpleMessaging();
|
||||
//TODO fix this hugly wiring
|
||||
handler.setMessaging(messaging);
|
||||
messaging.setNotifier(handler);
|
||||
@@ -89,6 +93,9 @@ public class Server {
|
||||
|
||||
protected void stopServer() {
|
||||
LOG.info("Server stopping...");
|
||||
|
||||
messaging.close();
|
||||
|
||||
for(IoSession session: m_acceptor.getManagedSessions().values()) {
|
||||
if(session.isConnected() && !session.isClosing()){
|
||||
session.close(false);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dna.mqtt.moquette.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.dna.mqtt.moquette.client.Client;
|
||||
import org.dna.mqtt.moquette.client.IPublishCallback;
|
||||
@@ -30,6 +31,10 @@ public class ServerIntegrationTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
server.stopServer();
|
||||
File dbFile = new File(Server.STORAGE_FILE_PATH);
|
||||
if (dbFile.exists()) {
|
||||
dbFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
@Grab(group='org.fusesource.hawtdb', module='hawtdb', version='1.6')
|
||||
|
||||
import org.fusesource.hawtbuf.codec.StringCodec
|
||||
import org.fusesource.hawtdb.api.BTreeIndexFactory
|
||||
import org.fusesource.hawtdb.api.PageFile
|
||||
import org.fusesource.hawtdb.api.PageFileFactory
|
||||
import org.fusesource.hawtdb.api.SortedIndex
|
||||
|
||||
|
||||
|
||||
File tmpFile = new File(System.getProperty("user.home") + File.separator + "test_hawtdb.dat")
|
||||
//tmpFile.createNewFile()
|
||||
|
||||
def writeSomeData(tmpFile) {
|
||||
def factory = new PageFileFactory()
|
||||
factory.file = tmpFile
|
||||
factory.open()
|
||||
def pageFile = factory.getPageFile()
|
||||
|
||||
BTreeIndexFactory<String, String> indexFactory = new BTreeIndexFactory<String, String>()
|
||||
indexFactory.setKeyCodec(StringCodec.INSTANCE)
|
||||
|
||||
SortedIndex<String, String> writeIndex = indexFactory.openOrCreate(pageFile)
|
||||
println "Hawt opened, try to read"
|
||||
println "Size: ${writeIndex.size()}"
|
||||
|
||||
println "write something"
|
||||
writeIndex.put("titolo", "capucetto rosso")
|
||||
pageFile.flush()
|
||||
|
||||
println "check after write content: ${writeIndex.get("titolo")}, size ${writeIndex.size()}"
|
||||
|
||||
//pageFile.close()
|
||||
factory.close()
|
||||
}
|
||||
|
||||
|
||||
def readAllFileContents(tmpFile) {
|
||||
def factory = new PageFileFactory()
|
||||
factory.file = tmpFile
|
||||
factory.open()
|
||||
def pageFile = factory.getPageFile()
|
||||
|
||||
BTreeIndexFactory<String, String> indexFactory = new BTreeIndexFactory<String, String>()
|
||||
indexFactory.setKeyCodec(StringCodec.INSTANCE)
|
||||
|
||||
SortedIndex<String, String> readingIndex = indexFactory.openOrCreate(pageFile)
|
||||
|
||||
println "read something, size ${readingIndex.size()}"
|
||||
for (def entry : readingIndex) {
|
||||
println "read k, v -> ${entry.key}, ${entry.value} "
|
||||
}
|
||||
|
||||
factory.close()
|
||||
}
|
||||
|
||||
|
||||
writeSomeData(tmpFile)
|
||||
readAllFileContents(tmpFile)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
@Grab(group='org.fusesource.hawtdb', module='hawtdb', version='1.6')
|
||||
|
||||
import org.fusesource.hawtbuf.codec.StringCodec
|
||||
import org.fusesource.hawtdb.api.BTreeIndexFactory
|
||||
import org.fusesource.hawtdb.api.PageFile
|
||||
import org.fusesource.hawtdb.api.PageFileFactory
|
||||
import org.fusesource.hawtdb.api.SortedIndex
|
||||
import org.fusesource.hawtbuf.Buffer
|
||||
|
||||
|
||||
|
||||
File tmpFile = new File(System.getProperty("user.home") + File.separator + "test_hawtdb.dat")
|
||||
//tmpFile.createNewFile()
|
||||
|
||||
def writeSomeData(tmpFile) {
|
||||
def factory = new PageFileFactory()
|
||||
factory.file = tmpFile
|
||||
factory.open()
|
||||
def pageFile = factory.getPageFile()
|
||||
int pageIdx = pageFile.alloc()
|
||||
pageFile.write(pageIdx, new Buffer("Test".getBytes()))
|
||||
println "writed at page index ${pageIdx}"
|
||||
pageFile.flush()
|
||||
pageFile.close()
|
||||
}
|
||||
|
||||
|
||||
def readTest(tmpFile) {
|
||||
def factory = new PageFileFactory()
|
||||
factory.file = tmpFile
|
||||
factory.open()
|
||||
def pageFile = factory.getPageFile()
|
||||
println "page size is: " + pageFile.pageSize
|
||||
Buffer b = new Buffer(512)
|
||||
pageFile.read(0, b)
|
||||
println "content try read " + b
|
||||
|
||||
pageFile.close()
|
||||
}
|
||||
|
||||
|
||||
writeSomeData(tmpFile)
|
||||
readTest(tmpFile)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user