Use MessagePack on disk

This commit is contained in:
Ken-Håvard Lieng 2016-01-17 23:33:52 +01:00
parent 1def24500a
commit 76f99c8332
55 changed files with 11993 additions and 85 deletions

View file

@ -17,7 +17,7 @@ func TestAddRemoveUser(t *testing.T) {
channelStore := NewChannelStore()
channelStore.AddUser("user", "srv", "#chan")
channelStore.AddUser("user2", "srv", "#chan")
assert.Equal(t, channelStore.GetUsers("srv", "#chan"), []string{"user", "user2"})
assert.Equal(t, []string{"user", "user2"}, channelStore.GetUsers("srv", "#chan"))
channelStore.RemoveUser("user", "srv", "#chan")
assert.Equal(t, []string{"user2"}, channelStore.GetUsers("srv", "#chan"))
}

48
storage/schema.go Normal file
View file

@ -0,0 +1,48 @@
package storage
import (
"crypto/tls"
"sync"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/blevesearch/bleve"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/boltdb/bolt"
)
//go:generate msgp
type User struct {
ID uint64
Username string
id []byte
messageLog *bolt.DB
messageIndex bleve.Index
certificate *tls.Certificate
lock sync.Mutex
}
type Server struct {
Name string `json:"name"`
Host string `json:"host"`
Port string `json:"port,omitempty"`
TLS bool `json:"tls"`
Password string `json:"password,omitempty"`
Nick string `json:"nick"`
Username string `json:"username"`
Realname string `json:"realname"`
}
type Channel struct {
Server string `json:"server"`
Name string `json:"name"`
Topic string `json:"topic,omitempty"`
}
type Message struct {
ID uint64 `json:"id"`
Server string `json:"server"`
From string `json:"from"`
To string `json:"to,omitempty"`
Content string `json:"content"`
Time int64 `json:"time"`
}

711
storage/schema_gen.go Normal file
View file

@ -0,0 +1,711 @@
package storage
// NOTE: THIS FILE WAS PRODUCED BY THE
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
// DO NOT EDIT
import (
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *Channel) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var isz uint32
isz, err = dc.ReadMapHeader()
if err != nil {
return
}
for isz > 0 {
isz--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "Server":
z.Server, err = dc.ReadString()
if err != nil {
return
}
case "Name":
z.Name, err = dc.ReadString()
if err != nil {
return
}
case "Topic":
z.Topic, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z Channel) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 3
// write "Server"
err = en.Append(0x83, 0xa6, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72)
if err != nil {
return err
}
err = en.WriteString(z.Server)
if err != nil {
return
}
// write "Name"
err = en.Append(0xa4, 0x4e, 0x61, 0x6d, 0x65)
if err != nil {
return err
}
err = en.WriteString(z.Name)
if err != nil {
return
}
// write "Topic"
err = en.Append(0xa5, 0x54, 0x6f, 0x70, 0x69, 0x63)
if err != nil {
return err
}
err = en.WriteString(z.Topic)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z Channel) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 3
// string "Server"
o = append(o, 0x83, 0xa6, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72)
o = msgp.AppendString(o, z.Server)
// string "Name"
o = append(o, 0xa4, 0x4e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Name)
// string "Topic"
o = append(o, 0xa5, 0x54, 0x6f, 0x70, 0x69, 0x63)
o = msgp.AppendString(o, z.Topic)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Channel) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var isz uint32
isz, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for isz > 0 {
isz--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "Server":
z.Server, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Name":
z.Name, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Topic":
z.Topic, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
func (z Channel) Msgsize() (s int) {
s = 1 + 7 + msgp.StringPrefixSize + len(z.Server) + 5 + msgp.StringPrefixSize + len(z.Name) + 6 + msgp.StringPrefixSize + len(z.Topic)
return
}
// DecodeMsg implements msgp.Decodable
func (z *Message) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var isz uint32
isz, err = dc.ReadMapHeader()
if err != nil {
return
}
for isz > 0 {
isz--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "ID":
z.ID, err = dc.ReadUint64()
if err != nil {
return
}
case "Server":
z.Server, err = dc.ReadString()
if err != nil {
return
}
case "From":
z.From, err = dc.ReadString()
if err != nil {
return
}
case "To":
z.To, err = dc.ReadString()
if err != nil {
return
}
case "Content":
z.Content, err = dc.ReadString()
if err != nil {
return
}
case "Time":
z.Time, err = dc.ReadInt64()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *Message) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 6
// write "ID"
err = en.Append(0x86, 0xa2, 0x49, 0x44)
if err != nil {
return err
}
err = en.WriteUint64(z.ID)
if err != nil {
return
}
// write "Server"
err = en.Append(0xa6, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72)
if err != nil {
return err
}
err = en.WriteString(z.Server)
if err != nil {
return
}
// write "From"
err = en.Append(0xa4, 0x46, 0x72, 0x6f, 0x6d)
if err != nil {
return err
}
err = en.WriteString(z.From)
if err != nil {
return
}
// write "To"
err = en.Append(0xa2, 0x54, 0x6f)
if err != nil {
return err
}
err = en.WriteString(z.To)
if err != nil {
return
}
// write "Content"
err = en.Append(0xa7, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74)
if err != nil {
return err
}
err = en.WriteString(z.Content)
if err != nil {
return
}
// write "Time"
err = en.Append(0xa4, 0x54, 0x69, 0x6d, 0x65)
if err != nil {
return err
}
err = en.WriteInt64(z.Time)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *Message) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 6
// string "ID"
o = append(o, 0x86, 0xa2, 0x49, 0x44)
o = msgp.AppendUint64(o, z.ID)
// string "Server"
o = append(o, 0xa6, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72)
o = msgp.AppendString(o, z.Server)
// string "From"
o = append(o, 0xa4, 0x46, 0x72, 0x6f, 0x6d)
o = msgp.AppendString(o, z.From)
// string "To"
o = append(o, 0xa2, 0x54, 0x6f)
o = msgp.AppendString(o, z.To)
// string "Content"
o = append(o, 0xa7, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74)
o = msgp.AppendString(o, z.Content)
// string "Time"
o = append(o, 0xa4, 0x54, 0x69, 0x6d, 0x65)
o = msgp.AppendInt64(o, z.Time)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Message) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var isz uint32
isz, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for isz > 0 {
isz--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "ID":
z.ID, bts, err = msgp.ReadUint64Bytes(bts)
if err != nil {
return
}
case "Server":
z.Server, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "From":
z.From, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "To":
z.To, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Content":
z.Content, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Time":
z.Time, bts, err = msgp.ReadInt64Bytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
func (z *Message) Msgsize() (s int) {
s = 1 + 3 + msgp.Uint64Size + 7 + msgp.StringPrefixSize + len(z.Server) + 5 + msgp.StringPrefixSize + len(z.From) + 3 + msgp.StringPrefixSize + len(z.To) + 8 + msgp.StringPrefixSize + len(z.Content) + 5 + msgp.Int64Size
return
}
// DecodeMsg implements msgp.Decodable
func (z *Server) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var isz uint32
isz, err = dc.ReadMapHeader()
if err != nil {
return
}
for isz > 0 {
isz--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "Name":
z.Name, err = dc.ReadString()
if err != nil {
return
}
case "Host":
z.Host, err = dc.ReadString()
if err != nil {
return
}
case "Port":
z.Port, err = dc.ReadString()
if err != nil {
return
}
case "TLS":
z.TLS, err = dc.ReadBool()
if err != nil {
return
}
case "Password":
z.Password, err = dc.ReadString()
if err != nil {
return
}
case "Nick":
z.Nick, err = dc.ReadString()
if err != nil {
return
}
case "Username":
z.Username, err = dc.ReadString()
if err != nil {
return
}
case "Realname":
z.Realname, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *Server) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 8
// write "Name"
err = en.Append(0x88, 0xa4, 0x4e, 0x61, 0x6d, 0x65)
if err != nil {
return err
}
err = en.WriteString(z.Name)
if err != nil {
return
}
// write "Host"
err = en.Append(0xa4, 0x48, 0x6f, 0x73, 0x74)
if err != nil {
return err
}
err = en.WriteString(z.Host)
if err != nil {
return
}
// write "Port"
err = en.Append(0xa4, 0x50, 0x6f, 0x72, 0x74)
if err != nil {
return err
}
err = en.WriteString(z.Port)
if err != nil {
return
}
// write "TLS"
err = en.Append(0xa3, 0x54, 0x4c, 0x53)
if err != nil {
return err
}
err = en.WriteBool(z.TLS)
if err != nil {
return
}
// write "Password"
err = en.Append(0xa8, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64)
if err != nil {
return err
}
err = en.WriteString(z.Password)
if err != nil {
return
}
// write "Nick"
err = en.Append(0xa4, 0x4e, 0x69, 0x63, 0x6b)
if err != nil {
return err
}
err = en.WriteString(z.Nick)
if err != nil {
return
}
// write "Username"
err = en.Append(0xa8, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65)
if err != nil {
return err
}
err = en.WriteString(z.Username)
if err != nil {
return
}
// write "Realname"
err = en.Append(0xa8, 0x52, 0x65, 0x61, 0x6c, 0x6e, 0x61, 0x6d, 0x65)
if err != nil {
return err
}
err = en.WriteString(z.Realname)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *Server) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 8
// string "Name"
o = append(o, 0x88, 0xa4, 0x4e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Name)
// string "Host"
o = append(o, 0xa4, 0x48, 0x6f, 0x73, 0x74)
o = msgp.AppendString(o, z.Host)
// string "Port"
o = append(o, 0xa4, 0x50, 0x6f, 0x72, 0x74)
o = msgp.AppendString(o, z.Port)
// string "TLS"
o = append(o, 0xa3, 0x54, 0x4c, 0x53)
o = msgp.AppendBool(o, z.TLS)
// string "Password"
o = append(o, 0xa8, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64)
o = msgp.AppendString(o, z.Password)
// string "Nick"
o = append(o, 0xa4, 0x4e, 0x69, 0x63, 0x6b)
o = msgp.AppendString(o, z.Nick)
// string "Username"
o = append(o, 0xa8, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Username)
// string "Realname"
o = append(o, 0xa8, 0x52, 0x65, 0x61, 0x6c, 0x6e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Realname)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Server) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var isz uint32
isz, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for isz > 0 {
isz--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "Name":
z.Name, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Host":
z.Host, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Port":
z.Port, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "TLS":
z.TLS, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
return
}
case "Password":
z.Password, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Nick":
z.Nick, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Username":
z.Username, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "Realname":
z.Realname, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
func (z *Server) Msgsize() (s int) {
s = 1 + 5 + msgp.StringPrefixSize + len(z.Name) + 5 + msgp.StringPrefixSize + len(z.Host) + 5 + msgp.StringPrefixSize + len(z.Port) + 4 + msgp.BoolSize + 9 + msgp.StringPrefixSize + len(z.Password) + 5 + msgp.StringPrefixSize + len(z.Nick) + 9 + msgp.StringPrefixSize + len(z.Username) + 9 + msgp.StringPrefixSize + len(z.Realname)
return
}
// DecodeMsg implements msgp.Decodable
func (z *User) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var isz uint32
isz, err = dc.ReadMapHeader()
if err != nil {
return
}
for isz > 0 {
isz--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "ID":
z.ID, err = dc.ReadUint64()
if err != nil {
return
}
case "Username":
z.Username, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z User) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 2
// write "ID"
err = en.Append(0x82, 0xa2, 0x49, 0x44)
if err != nil {
return err
}
err = en.WriteUint64(z.ID)
if err != nil {
return
}
// write "Username"
err = en.Append(0xa8, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65)
if err != nil {
return err
}
err = en.WriteString(z.Username)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z User) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 2
// string "ID"
o = append(o, 0x82, 0xa2, 0x49, 0x44)
o = msgp.AppendUint64(o, z.ID)
// string "Username"
o = append(o, 0xa8, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Username)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *User) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var isz uint32
isz, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for isz > 0 {
isz--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "ID":
z.ID, bts, err = msgp.ReadUint64Bytes(bts)
if err != nil {
return
}
case "Username":
z.Username, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
func (z User) Msgsize() (s int) {
s = 1 + 3 + msgp.Uint64Size + 9 + msgp.StringPrefixSize + len(z.Username)
return
}

464
storage/schema_gen_test.go Normal file
View file

@ -0,0 +1,464 @@
package storage
// NOTE: THIS FILE WAS PRODUCED BY THE
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
// DO NOT EDIT
import (
"bytes"
"testing"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshalChannel(t *testing.T) {
v := Channel{}
bts, err := v.MarshalMsg(nil)
if err != nil {
t.Fatal(err)
}
left, err := v.UnmarshalMsg(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
}
left, err = msgp.Skip(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
}
}
func BenchmarkMarshalMsgChannel(b *testing.B) {
v := Channel{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgChannel(b *testing.B) {
v := Channel{}
bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
bts, _ = v.MarshalMsg(bts[0:0])
}
}
func BenchmarkUnmarshalChannel(b *testing.B) {
v := Channel{}
bts, _ := v.MarshalMsg(nil)
b.ReportAllocs()
b.SetBytes(int64(len(bts)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := v.UnmarshalMsg(bts)
if err != nil {
b.Fatal(err)
}
}
}
func TestEncodeDecodeChannel(t *testing.T) {
v := Channel{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Logf("WARNING: Msgsize() for %v is inaccurate", v)
}
vn := Channel{}
err := msgp.Decode(&buf, &vn)
if err != nil {
t.Error(err)
}
buf.Reset()
msgp.Encode(&buf, &v)
err = msgp.NewReader(&buf).Skip()
if err != nil {
t.Error(err)
}
}
func BenchmarkEncodeChannel(b *testing.B) {
v := Channel{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
en := msgp.NewWriter(msgp.Nowhere)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.EncodeMsg(en)
}
en.Flush()
}
func BenchmarkDecodeChannel(b *testing.B) {
v := Channel{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
rd := msgp.NewEndlessReader(buf.Bytes(), b)
dc := msgp.NewReader(rd)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := v.DecodeMsg(dc)
if err != nil {
b.Fatal(err)
}
}
}
func TestMarshalUnmarshalMessage(t *testing.T) {
v := Message{}
bts, err := v.MarshalMsg(nil)
if err != nil {
t.Fatal(err)
}
left, err := v.UnmarshalMsg(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
}
left, err = msgp.Skip(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
}
}
func BenchmarkMarshalMsgMessage(b *testing.B) {
v := Message{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMessage(b *testing.B) {
v := Message{}
bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
bts, _ = v.MarshalMsg(bts[0:0])
}
}
func BenchmarkUnmarshalMessage(b *testing.B) {
v := Message{}
bts, _ := v.MarshalMsg(nil)
b.ReportAllocs()
b.SetBytes(int64(len(bts)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := v.UnmarshalMsg(bts)
if err != nil {
b.Fatal(err)
}
}
}
func TestEncodeDecodeMessage(t *testing.T) {
v := Message{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Logf("WARNING: Msgsize() for %v is inaccurate", v)
}
vn := Message{}
err := msgp.Decode(&buf, &vn)
if err != nil {
t.Error(err)
}
buf.Reset()
msgp.Encode(&buf, &v)
err = msgp.NewReader(&buf).Skip()
if err != nil {
t.Error(err)
}
}
func BenchmarkEncodeMessage(b *testing.B) {
v := Message{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
en := msgp.NewWriter(msgp.Nowhere)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.EncodeMsg(en)
}
en.Flush()
}
func BenchmarkDecodeMessage(b *testing.B) {
v := Message{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
rd := msgp.NewEndlessReader(buf.Bytes(), b)
dc := msgp.NewReader(rd)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := v.DecodeMsg(dc)
if err != nil {
b.Fatal(err)
}
}
}
func TestMarshalUnmarshalServer(t *testing.T) {
v := Server{}
bts, err := v.MarshalMsg(nil)
if err != nil {
t.Fatal(err)
}
left, err := v.UnmarshalMsg(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
}
left, err = msgp.Skip(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
}
}
func BenchmarkMarshalMsgServer(b *testing.B) {
v := Server{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgServer(b *testing.B) {
v := Server{}
bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
bts, _ = v.MarshalMsg(bts[0:0])
}
}
func BenchmarkUnmarshalServer(b *testing.B) {
v := Server{}
bts, _ := v.MarshalMsg(nil)
b.ReportAllocs()
b.SetBytes(int64(len(bts)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := v.UnmarshalMsg(bts)
if err != nil {
b.Fatal(err)
}
}
}
func TestEncodeDecodeServer(t *testing.T) {
v := Server{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Logf("WARNING: Msgsize() for %v is inaccurate", v)
}
vn := Server{}
err := msgp.Decode(&buf, &vn)
if err != nil {
t.Error(err)
}
buf.Reset()
msgp.Encode(&buf, &v)
err = msgp.NewReader(&buf).Skip()
if err != nil {
t.Error(err)
}
}
func BenchmarkEncodeServer(b *testing.B) {
v := Server{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
en := msgp.NewWriter(msgp.Nowhere)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.EncodeMsg(en)
}
en.Flush()
}
func BenchmarkDecodeServer(b *testing.B) {
v := Server{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
rd := msgp.NewEndlessReader(buf.Bytes(), b)
dc := msgp.NewReader(rd)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := v.DecodeMsg(dc)
if err != nil {
b.Fatal(err)
}
}
}
func TestMarshalUnmarshalUser(t *testing.T) {
v := User{}
bts, err := v.MarshalMsg(nil)
if err != nil {
t.Fatal(err)
}
left, err := v.UnmarshalMsg(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
}
left, err = msgp.Skip(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
}
}
func BenchmarkMarshalMsgUser(b *testing.B) {
v := User{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgUser(b *testing.B) {
v := User{}
bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
bts, _ = v.MarshalMsg(bts[0:0])
}
}
func BenchmarkUnmarshalUser(b *testing.B) {
v := User{}
bts, _ := v.MarshalMsg(nil)
b.ReportAllocs()
b.SetBytes(int64(len(bts)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := v.UnmarshalMsg(bts)
if err != nil {
b.Fatal(err)
}
}
}
func TestEncodeDecodeUser(t *testing.T) {
v := User{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Logf("WARNING: Msgsize() for %v is inaccurate", v)
}
vn := User{}
err := msgp.Decode(&buf, &vn)
if err != nil {
t.Error(err)
}
buf.Reset()
msgp.Encode(&buf, &v)
err = msgp.NewReader(&buf).Skip()
if err != nil {
t.Error(err)
}
}
func BenchmarkEncodeUser(b *testing.B) {
v := User{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
en := msgp.NewWriter(msgp.Nowhere)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.EncodeMsg(en)
}
en.Flush()
}
func BenchmarkDecodeUser(b *testing.B) {
v := User{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
rd := msgp.NewEndlessReader(buf.Bytes(), b)
dc := msgp.NewReader(rd)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := v.DecodeMsg(dc)
if err != nil {
b.Fatal(err)
}
}
}

View file

@ -2,54 +2,21 @@ package storage
import (
"bytes"
"crypto/tls"
"encoding/json"
"strconv"
"sync"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/blevesearch/bleve"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/boltdb/bolt"
)
type User struct {
ID uint64
Username string
id []byte
messageLog *bolt.DB
messageIndex bleve.Index
certificate *tls.Certificate
lock sync.Mutex
}
type Server struct {
Name string `json:"name"`
Host string `json:"host"`
Port string `json:"port,omitempty"`
TLS bool `json:"tls"`
Password string `json:"password,omitempty"`
Nick string `json:"nick"`
Username string `json:"username"`
Realname string `json:"realname"`
}
type Channel struct {
Server string `json:"server"`
Name string `json:"name"`
Users []string `json:"users,omitempty"`
Topic string `json:"topic,omitempty"`
}
func NewUser() (*User, error) {
user := &User{}
err := db.Update(func(tx *bolt.Tx) error {
err := db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketUsers)
user.ID, _ = b.NextSequence()
user.Username = strconv.FormatUint(user.ID, 10)
data, err := json.Marshal(user)
data, err := user.MarshalMsg(nil)
if err != nil {
return err
}
@ -108,8 +75,8 @@ func (u *User) GetServers() []Server {
c := tx.Bucket(bucketServers).Cursor()
for k, v := c.Seek(u.id); bytes.HasPrefix(k, u.id); k, v = c.Next() {
var server Server
json.Unmarshal(v, &server)
server := Server{}
server.UnmarshalMsg(v)
servers = append(servers, server)
}
@ -126,8 +93,8 @@ func (u *User) GetChannels() []Channel {
c := tx.Bucket(bucketChannels).Cursor()
for k, v := c.Seek(u.id); bytes.HasPrefix(k, u.id); k, v = c.Next() {
var channel Channel
json.Unmarshal(v, &channel)
channel := Channel{}
channel.UnmarshalMsg(v)
channels = append(channels, channel)
}
@ -138,9 +105,9 @@ func (u *User) GetChannels() []Channel {
}
func (u *User) AddServer(server Server) {
db.Update(func(tx *bolt.Tx) error {
db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketServers)
data, _ := json.Marshal(server)
data, _ := server.MarshalMsg(nil)
b.Put(u.serverID(server.Host), data)
@ -149,9 +116,9 @@ func (u *User) AddServer(server Server) {
}
func (u *User) AddChannel(channel Channel) {
db.Update(func(tx *bolt.Tx) error {
db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketChannels)
data, _ := json.Marshal(channel)
data, _ := channel.MarshalMsg(nil)
b.Put(u.channelID(channel.Server, channel.Name), data)
@ -160,15 +127,15 @@ func (u *User) AddChannel(channel Channel) {
}
func (u *User) SetNick(nick, address string) {
db.Update(func(tx *bolt.Tx) error {
db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketServers)
id := u.serverID(address)
var server Server
json.Unmarshal(b.Get(id), &server)
server := Server{}
server.UnmarshalMsg(b.Get(id))
server.Nick = nick
data, _ := json.Marshal(server)
data, _ := server.MarshalMsg(nil)
b.Put(id, data)
return nil
@ -176,7 +143,7 @@ func (u *User) SetNick(nick, address string) {
}
func (u *User) RemoveServer(address string) {
db.Update(func(tx *bolt.Tx) error {
db.Batch(func(tx *bolt.Tx) error {
serverID := u.serverID(address)
tx.Bucket(bucketServers).Delete(serverID)
@ -192,7 +159,7 @@ func (u *User) RemoveServer(address string) {
}
func (u *User) RemoveChannel(server, channel string) {
db.Update(func(tx *bolt.Tx) error {
db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketChannels)
id := u.channelID(server, channel)

View file

@ -1,7 +1,6 @@
package storage
import (
"encoding/json"
"os"
"strconv"
"strings"
@ -11,15 +10,6 @@ import (
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/boltdb/bolt"
)
type Message struct {
ID uint64 `json:"id"`
Server string `json:"server"`
From string `json:"from"`
To string `json:"to,omitempty"`
Content string `json:"content"`
Time int64 `json:"time"`
}
func (u *User) LogMessage(server, from, to, content string) error {
message := Message{
Server: server,
@ -38,7 +28,7 @@ func (u *User) LogMessage(server, from, to, content string) error {
message.ID, _ = b.NextSequence()
data, err := json.Marshal(message)
data, err := message.MarshalMsg(nil)
if err != nil {
return err
}
@ -66,7 +56,7 @@ func (u *User) GetLastMessages(server, channel string, count int) ([]Message, er
for _, v := c.Last(); count > 0 && v != nil; _, v = c.Prev() {
count--
json.Unmarshal(v, &messages[count])
messages[count].UnmarshalMsg(v)
}
return nil
@ -93,7 +83,7 @@ func (u *User) GetMessages(server, channel string, count int, fromID uint64) ([]
for k, v := c.Prev(); count > 0 && k != nil; k, v = c.Prev() {
count--
json.Unmarshal(v, &messages[count])
messages[count].UnmarshalMsg(v)
}
return nil
@ -131,8 +121,8 @@ func (u *User) SearchMessages(server, channel, phrase string) ([]Message, error)
bc := b.Bucket([]byte(hit.ID[:idx]))
id, _ := strconv.ParseUint(hit.ID[idx+1:], 10, 64)
var message Message
json.Unmarshal(bc.Get(idToBytes(id)), &message)
message := Message{}
message.UnmarshalMsg(bc.Get(idToBytes(id)))
messages = append(messages, message)
}

View file

@ -102,6 +102,8 @@ func TestMessages(t *testing.T) {
assert.Len(t, messages, 5)
messages, err = user.GetMessages("irc.freenode.net", "#go-nuts", 10, 100)
assert.Equal(t, "message0", messages[0].Content)
assert.Equal(t, "message4", messages[4].Content)
assert.Nil(t, err)
assert.Len(t, messages, 5)