Fixed implementation for HawtDB storage of subscriptions

This commit is contained in:
selva.andre
2012-08-13 23:42:55 +02:00
parent 389c906d8f
commit 025b5c77ff
8 changed files with 164 additions and 17 deletions
@@ -27,4 +27,6 @@ public interface IMessaging {
* was subscribed * was subscribed
*/ */
void removeSubscriptions(String clientID); void removeSubscriptions(String clientID);
void close();
} }
@@ -58,4 +58,10 @@ public class SimpleMessaging implements IMessaging {
subscriptions.removeForClient(clientID); subscriptions.removeForClient(clientID);
rwLock.writeLock().unlock(); 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; package org.dna.mqtt.moquette.messaging.spi.impl;
import java.io.Serializable;
import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType; import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
/** /**
@@ -9,7 +10,7 @@ import org.dna.mqtt.moquette.proto.messages.AbstractMessage.QOSType;
* *
* @author andrea * @author andrea
*/ */
public class Subscription { public class Subscription implements Serializable {
QOSType requestedQos; QOSType requestedQos;
String clientId; String clientId;
@@ -9,8 +9,10 @@ import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import org.dna.mqtt.moquette.MQTTException; import org.dna.mqtt.moquette.MQTTException;
import org.dna.mqtt.moquette.server.MQTTHandler; import org.dna.mqtt.moquette.server.MQTTHandler;
import org.dna.mqtt.moquette.server.Server;
import org.fusesource.hawtbuf.codec.StringCodec; import org.fusesource.hawtbuf.codec.StringCodec;
import org.fusesource.hawtdb.api.BTreeIndexFactory; import org.fusesource.hawtdb.api.BTreeIndexFactory;
import org.fusesource.hawtdb.api.PageFile; import org.fusesource.hawtdb.api.PageFile;
@@ -197,29 +199,34 @@ public class SubscriptionsStore {
} }
// private List<Subscription> subscriptions = new ArrayList<Subscription>(); // private List<Subscription> subscriptions = new ArrayList<Subscription>();
private TreeNode subscriptions = new TreeNode(null); private TreeNode subscriptions = new TreeNode(null);
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionsStore.class); private static final Logger LOG = LoggerFactory.getLogger(SubscriptionsStore.class);
//pesistent Map of clientID, list of Subscriptions //pesistent Map of clientID, list of Subscriptions
private SortedIndex<String, List<Subscription>> m_persistent; 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 * Initialize basic store structures, like the FS storage to maintain
* client's topics subscriptions * client's topics subscriptions
*/ */
public void init() { 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; File tmpFile;
try { try {
tmpFile = File.createTempFile("hawtdb", "test"); tmpFile = new File(storeFile.toString());
tmpFile.createNewFile();
} catch (IOException ex) { } catch (IOException ex) {
LOG.error(null, 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.setFile(/*new File("mydb.dat")*/tmpFile);
factory.open(); factory.open();
pageFile = factory.getPageFile(); PageFile pageFile = factory.getPageFile();
// HashIndexFactory<String, List<Subscription>> indexFactory = // HashIndexFactory<String, List<Subscription>> indexFactory =
// new HashIndexFactory<String, List<Subscription>>(); // new HashIndexFactory<String, List<Subscription>>();
@@ -231,7 +238,7 @@ public class SubscriptionsStore {
//reaload any subscriptions persisted //reaload any subscriptions persisted
LOG.debug("Reloading all stored subscriptions..."); 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()) { for (Subscription subscription : entry.getValue()) {
addDirect(subscription); addDirect(subscription);
} }
@@ -239,6 +246,14 @@ public class SubscriptionsStore {
LOG.debug("Finished loading"); 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) { protected void addDirect(Subscription newSubscription) {
List<Token> tokens = new ArrayList<Token>(); List<Token> tokens = new ArrayList<Token>();
@@ -278,7 +293,8 @@ public class SubscriptionsStore {
List<Subscription> subs = m_persistent.get(clientID); List<Subscription> subs = m_persistent.get(clientID);
subs.add(newSubscription); subs.add(newSubscription);
pageFile.flush(); m_persistent.put(clientID, subs);
// pageFile.flush();
} }
/** /**
@@ -1,5 +1,6 @@
package org.dna.mqtt.moquette.server; package org.dna.mqtt.moquette.server;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.service.IoAcceptor;
@@ -36,7 +37,10 @@ public class Server {
public static final int PORT = 9191; public static final int PORT = 9191;
public static final int DEFAULT_CONNECT_TIMEOUT = 10; 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; private IoAcceptor m_acceptor;
SimpleMessaging messaging;
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
new Server().startServer(); new Server().startServer();
@@ -64,7 +68,7 @@ public class Server {
m_acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(encoder, decoder)); m_acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(encoder, decoder));
MQTTHandler handler = new MQTTHandler(); MQTTHandler handler = new MQTTHandler();
SimpleMessaging messaging = new SimpleMessaging(); messaging = new SimpleMessaging();
//TODO fix this hugly wiring //TODO fix this hugly wiring
handler.setMessaging(messaging); handler.setMessaging(messaging);
messaging.setNotifier(handler); messaging.setNotifier(handler);
@@ -89,6 +93,9 @@ public class Server {
protected void stopServer() { protected void stopServer() {
LOG.info("Server stopping..."); LOG.info("Server stopping...");
messaging.close();
for(IoSession session: m_acceptor.getManagedSessions().values()) { for(IoSession session: m_acceptor.getManagedSessions().values()) {
if(session.isConnected() && !session.isClosing()){ if(session.isConnected() && !session.isClosing()){
session.close(false); session.close(false);
@@ -1,5 +1,6 @@
package org.dna.mqtt.moquette.server; package org.dna.mqtt.moquette.server;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.dna.mqtt.moquette.client.Client; import org.dna.mqtt.moquette.client.Client;
import org.dna.mqtt.moquette.client.IPublishCallback; import org.dna.mqtt.moquette.client.IPublishCallback;
@@ -30,6 +31,10 @@ public class ServerIntegrationTest {
@After @After
public void tearDown() { public void tearDown() {
server.stopServer(); server.stopServer();
File dbFile = new File(Server.STORAGE_FILE_PATH);
if (dbFile.exists()) {
dbFile.delete();
}
} }
+65
View File
@@ -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)
+45
View File
@@ -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)