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
*/
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;
@@ -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();
}
}
+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)