[smuxi/experiments/sqlite: 27/27] Engine(-Tests): initial SqliteMessageBuffer implementation (closes: #908) WIP



commit 3e9e5d3c569a3ee8adec8312bd402ff2f3e2e024
Author: Mirco Bauer <meebey meebey net>
Date:   Sun Feb 23 17:49:21 2014 +0100

    Engine(-Tests): initial SqliteMessageBuffer implementation (closes: #908) WIP

 src/Engine-Tests/Engine-Tests.csproj             |    1 +
 src/Engine-Tests/SqliteMessageBufferTests.cs     |  100 ++++++++++
 src/Engine/Engine.csproj                         |    1 +
 src/Engine/MessageBuffers/SqliteMessageBuffer.cs |  232 ++++++++++++++++++++++
 4 files changed, 334 insertions(+), 0 deletions(-)
---
diff --git a/src/Engine-Tests/Engine-Tests.csproj b/src/Engine-Tests/Engine-Tests.csproj
index 040336f..1c30005 100644
--- a/src/Engine-Tests/Engine-Tests.csproj
+++ b/src/Engine-Tests/Engine-Tests.csproj
@@ -44,6 +44,7 @@
     <Compile Include="GitMessageBufferTests.cs" />
     <Compile Include="JsonMessageBufferTests.cs" />
     <Compile Include="MessageDtoModelV1Tests.cs" />
+    <Compile Include="SqliteMessageBufferTests.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/Engine-Tests/SqliteMessageBufferTests.cs b/src/Engine-Tests/SqliteMessageBufferTests.cs
new file mode 100644
index 0000000..49be73e
--- /dev/null
+++ b/src/Engine-Tests/SqliteMessageBufferTests.cs
@@ -0,0 +1,100 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2014 Mirco Bauer <meebey meebey net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using NUnit.Framework;
+using Smuxi.Common;
+
+namespace Smuxi.Engine
+{
+    [TestFixture]
+    public class SqliteMessageBufferTests : MessageBufferTestsBase
+    {
+        protected override IMessageBuffer CreateBuffer()
+        {
+            var dbFile = Path.Combine(Platform.GetBuffersPath("testuser"),
+                                      "testprot");
+            dbFile = Path.Combine(dbFile, "testnet");
+            dbFile = Path.Combine(dbFile, "testchat.sqlite3");
+            if (File.Exists(dbFile)) {
+                File.Delete(dbFile);
+            }
+
+            return OpenBuffer();
+        }
+
+        protected override IMessageBuffer OpenBuffer()
+        {
+            return new SqliteMessageBuffer("testuser", "testprot", "testnet", "testchat");
+        }
+
+        [Test]
+        public void Reopen()
+        {
+            Buffer.Dispose();
+            OpenBuffer();
+            Enumerator();
+        }
+
+        [Test]
+        public void ImplicitFlush()
+        {
+            // generate 32 extra messsages to exceed the buffer size which
+            // forces a flush of the buffer to db4o
+            var bufferCount = Buffer.Count;
+            var msgs = new List<MessageModel>(Buffer);
+            for (int i = 1; i <= 32; i++) {
+                var builder = new MessageBuilder();
+                builder.AppendText("msg{0}", bufferCount + i);
+                var msg = builder.ToMessage();
+                msgs.Add(msg);
+                Buffer.Add(msg);
+            }
+
+            int j = 0;
+            foreach (var msg in Buffer) {
+                Assert.AreEqual(msgs[j++].ToString(), msg.ToString());
+            }
+            Assert.AreEqual(msgs.Count, j);
+        }
+
+        [Test]
+        public void ImplicitRemoveAt()
+        {
+            Buffer.MaxCapacity = 16;
+            // generate 32 extra messsages to exceed the max capacity which
+            // forces a RemoveAt() call of the oldest messages
+            var bufferCount = Buffer.Count;
+            var msgs = new List<MessageModel>(Buffer);
+            for (int i = 1; i <= 32; i++) {
+                var builder = new MessageBuilder();
+                builder.AppendText("msg{0}", bufferCount + i);
+                var msg = builder.ToMessage();
+                msgs.Add(msg);
+                Buffer.Add(msg);
+            }
+
+            Assert.AreEqual(Buffer.MaxCapacity, Buffer.Count);
+            Assert.AreEqual(msgs[19].ToString(), Buffer[0].ToString());
+        }
+    }
+}
diff --git a/src/Engine/Engine.csproj b/src/Engine/Engine.csproj
index 2c74ef3..ff441e0 100644
--- a/src/Engine/Engine.csproj
+++ b/src/Engine/Engine.csproj
@@ -112,6 +112,7 @@
     <Compile Include="MessageBuffers\GitMessageBuffer.cs" />
     <Compile Include="MessageBuffers\JsonMessageBuffer.cs" />
     <Compile Include="Messages\Dto\MessageDtoModelV1.cs" />
+    <Compile Include="MessageBuffers\SqliteMessageBuffer.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Protocols\" />
diff --git a/src/Engine/MessageBuffers/SqliteMessageBuffer.cs 
b/src/Engine/MessageBuffers/SqliteMessageBuffer.cs
new file mode 100644
index 0000000..fb00217
--- /dev/null
+++ b/src/Engine/MessageBuffers/SqliteMessageBuffer.cs
@@ -0,0 +1,232 @@
+// Smuxi - Smart MUltipleXed Irc
+// 
+// Copyright (c) 2014 Mirco Bauer <meebey meebey net>
+// 
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+using System;
+using System.IO;
+using System.Text;
+using System.Linq;
+using System.Collections.Generic;
+using Mono.Data.Sqlite;
+using ServiceStack.Text;
+using Smuxi.Engine.Dto;
+
+namespace Smuxi.Engine
+{
+       public class SqliteMessageBuffer : MessageBufferBase
+    {
+#if LOG4NET
+        static readonly log4net.ILog f_Logger = 
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+#endif
+        string DBPath { get; set; }
+        SqliteConnection Connection { get; set; }
+
+        public override int Count {
+            get {
+                var cmd = Connection.CreateCommand();
+                cmd.CommandText = "SELECT COUNT(*) FROM Messages";
+                return (int) Convert.ChangeType(cmd.ExecuteScalar(), typeof(int));
+            }
+        }
+
+        public override MessageModel this[int index] {
+            get {
+                return GetRange(index, 1).First();
+            }
+            set {
+                throw new NotImplementedException();
+            }
+        }
+
+               public SqliteMessageBuffer(string sessionUsername, string protocol,
+                                 string networkId, string chatId) :
+                            base(sessionUsername, protocol, networkId, chatId)
+        {
+            DBPath = GetBufferPath() + ".sqlite3";
+            Connection = new SqliteConnection("URI=file:" + DBPath);
+            Connection.Open();
+
+            var sql = "CREATE TABLE IF NOT EXISTS Messages (" +
+                          "ID INTEGER PRIMARY KEY," +
+                          "JSON TEXT" +
+                      ")";
+            var cmd = Connection.CreateCommand();
+            cmd.CommandText = sql;
+            cmd.ExecuteNonQuery();
+        }
+
+        /*
+        void SerializeChunk(List<MessageDtoModelV1> chunk, TextWriter writer)
+        {
+            DateTime start, stop;
+            start = DateTime.UtcNow;
+            JsonSerializer.SerializeToWriter(chunk, writer);
+            stop = DateTime.UtcNow;
+#if LOG4NET && MSGBUF_DEBUG
+            f_Logger.DebugFormat("SerializeChunk(): {0} items took: {1:0.00} ms",
+                                 chunk.Count,
+                                 (stop - start).TotalMilliseconds);
+#endif
+        }
+
+        List<MessageDtoModelV1> DeserializeChunk(TextReader reader)
+        {
+            DateTime start, stop;
+            start = DateTime.UtcNow;
+            var chunk = JsonSerializer.DeserializeFromReader<List<MessageDtoModelV1>>(reader);
+            stop = DateTime.UtcNow;
+#if LOG4NET && MSGBUF_DEBUG
+            f_Logger.DebugFormat("DeserializeChunk(): {0} items took: {1:0.00} ms",
+                                 chunk.Count,
+                                 (stop - start).TotalMilliseconds);
+#endif
+            return chunk;
+        }
+
+        List<MessageModel> LoadChunk(Int64 offset)
+        {
+            var chunk = new List<MessageModel>(MaxChunkSize);
+            var chunkFileName = GetChunkFileName(offset);
+            var chunkFilePath = Path.Combine(ChunkBasePath, chunkFileName);
+            if (!File.Exists(chunkFilePath)) {
+                return chunk;
+            }
+            using (var reader = File.OpenRead(chunkFilePath))
+            using (var textReader = new StreamReader(reader)) {
+                var dtoMsgs = DeserializeChunk(textReader);
+                foreach (var dtoMsg in dtoMsgs) {
+                    chunk.Add(dtoMsg.ToMessage());
+                }
+            }
+            return chunk;
+        }
+
+        List<MessageDtoModelV1> LoadDtoChunk(Int64 offset)
+        {
+            var chunkFileName = GetChunkFileName(offset);
+            var chunkFilePath = Path.Combine(ChunkBasePath, chunkFileName);
+            if (!File.Exists(chunkFilePath)) {
+                return new List<MessageDtoModelV1>(0);
+            }
+            using (var reader = File.OpenRead(chunkFilePath))
+            using (var textReader = new StreamReader(reader)) {
+                return DeserializeChunk(textReader);
+            }
+        }
+*/
+
+        public override void Add(MessageModel msg)
+        {
+            if (msg == null) {
+                throw new ArgumentNullException("msg");
+            }
+
+            var dto = new MessageDtoModelV1(msg);
+            var json = JsonSerializer.SerializeToString(dto);
+
+            var cmd = Connection.CreateCommand();
+            cmd.CommandText = "INSERT INTO Messages (JSON)" +
+                              " VALUES(@json)";
+            var param = cmd.CreateParameter();
+            param.ParameterName = "json";
+            param.Value = json;
+            cmd.Parameters.Add(param);
+
+            cmd.ExecuteNonQuery();
+        }
+
+        public override IList<MessageModel> GetRange(int offset, int limit)
+        {
+            using (var cmd = Connection.CreateCommand()) {
+                cmd.CommandText = "SELECT ID, JSON FROM Messages " +
+                                  " ORDER BY ID" +
+                                  " LIMIT @limit OFFSET @offset ";
+                var param = cmd.CreateParameter();
+                param.ParameterName = "offset";
+                param.Value = offset.ToString();
+                cmd.Parameters.Add(param);
+
+                param = cmd.CreateParameter();
+                param.ParameterName = "limit";
+                param.Value = limit.ToString();
+                cmd.Parameters.Add(param);
+
+                var reader = cmd.ExecuteReader();
+                var msgs = new List<MessageModel>(limit);
+                while (reader.Read()) {
+                    var json = (string) reader["JSON"];
+                    var dto = JsonSerializer.DeserializeFromString<MessageDtoModelV1>(json);
+                    var msg = dto.ToMessage();
+                    msgs.Add(msg);
+                }
+                return msgs;
+            }
+        }
+
+        public override void Clear()
+        {
+            var cmd = Connection.CreateCommand();
+            cmd.CommandText = "DELETE FROM Messages";
+            cmd.ExecuteNonQuery();
+        }
+
+        public override bool Contains(MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void CopyTo(MessageModel[] array, int arrayIndex)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override bool Remove(MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override IEnumerator<MessageModel> GetEnumerator()
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override int IndexOf(MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void Insert(int index, MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void RemoveAt(int index)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override void Dispose()
+        {
+            Flush();
+        }
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]