summaryrefslogtreecommitdiffstats
path: root/store/redis_supplier.go
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2017-07-31 08:15:23 -0700
committerGitHub <noreply@github.com>2017-07-31 08:15:23 -0700
commit09b49c26ddfdb20ced61e7dfd4192e750ce40449 (patch)
tree1288d069cc8a199b8eb3b858935dffd377ee3d2d /store/redis_supplier.go
parent6f4e38d129ffaf469d40fc8596d3957ee94d21e9 (diff)
downloadchat-09b49c26ddfdb20ced61e7dfd4192e750ce40449.tar.gz
chat-09b49c26ddfdb20ced61e7dfd4192e750ce40449.tar.bz2
chat-09b49c26ddfdb20ced61e7dfd4192e750ce40449.zip
PLT-5308 Caching layer part 2 (#6973)
* Adding Reaction store cache layer example * Implementing reaction store in new caching system. * Redis for reaction store * Adding redis library * Adding invalidation for DeleteAllWithEmojiName and other minor enhancements
Diffstat (limited to 'store/redis_supplier.go')
-rw-r--r--store/redis_supplier.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/store/redis_supplier.go b/store/redis_supplier.go
new file mode 100644
index 000000000..eede36ef2
--- /dev/null
+++ b/store/redis_supplier.go
@@ -0,0 +1,133 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package store
+
+import (
+ "bytes"
+ "context"
+ "encoding/gob"
+
+ "time"
+
+ l4g "github.com/alecthomas/log4go"
+ "github.com/go-redis/redis"
+ "github.com/mattermost/platform/model"
+)
+
+const REDIS_EXPIRY_TIME = 30 * time.Minute
+
+type RedisSupplier struct {
+ next LayeredStoreSupplier
+ client *redis.Client
+}
+
+func GetBytes(key interface{}) ([]byte, error) {
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ err := enc.Encode(key)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func DecodeBytes(input []byte, thing interface{}) error {
+ dec := gob.NewDecoder(bytes.NewReader(input))
+ err := dec.Decode(thing)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func NewRedisSupplier() *RedisSupplier {
+ supplier := &RedisSupplier{}
+
+ supplier.client = redis.NewClient(&redis.Options{
+ Addr: "localhost:6379",
+ Password: "",
+ DB: 0,
+ })
+
+ if _, err := supplier.client.Ping().Result(); err != nil {
+ l4g.Error("Unable to ping redis server: " + err.Error())
+ return nil
+ }
+
+ return supplier
+}
+
+func (s *RedisSupplier) save(key string, value interface{}, expiry time.Duration) error {
+ if bytes, err := GetBytes(value); err != nil {
+ return err
+ } else {
+ if err := s.client.Set(key, bytes, expiry).Err(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (s *RedisSupplier) load(key string, writeTo interface{}) (bool, error) {
+ if data, err := s.client.Get(key).Bytes(); err != nil {
+ if err == redis.Nil {
+ return false, nil
+ } else {
+ return false, err
+ }
+ } else {
+ if err := DecodeBytes(data, writeTo); err != nil {
+ return false, err
+ }
+ }
+ return true, nil
+}
+
+func (s *RedisSupplier) SetChainNext(next LayeredStoreSupplier) {
+ s.next = next
+}
+
+func (s *RedisSupplier) Next() LayeredStoreSupplier {
+ return s.next
+}
+
+func (s *RedisSupplier) ReactionSave(ctx context.Context, reaction *model.Reaction, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
+ if err := s.client.Del("reactions:" + reaction.PostId).Err(); err != nil {
+ l4g.Error("Redis failed to remove key reactions:" + reaction.PostId + " Error: " + err.Error())
+ }
+ return s.Next().ReactionSave(ctx, reaction, hints...)
+}
+
+func (s *RedisSupplier) ReactionDelete(ctx context.Context, reaction *model.Reaction, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
+ if err := s.client.Del("reactions:" + reaction.PostId).Err(); err != nil {
+ l4g.Error("Redis failed to remove key reactions:" + reaction.PostId + " Error: " + err.Error())
+ }
+ return s.Next().ReactionDelete(ctx, reaction, hints...)
+}
+
+func (s *RedisSupplier) ReactionGetForPost(ctx context.Context, postId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
+ var resultdata []*model.Reaction
+ found, err := s.load("reactions:"+postId, &resultdata)
+ if found {
+ result := NewSupplierResult()
+ result.Data = resultdata
+ return result
+ }
+ if err != nil {
+ l4g.Error("Redis encountered an error on read: " + err.Error())
+ }
+
+ result := s.Next().ReactionGetForPost(ctx, postId, hints...)
+
+ if err := s.save("reactions:"+postId, result.Data, REDIS_EXPIRY_TIME); err != nil {
+ l4g.Error("Redis encountered and error on write: " + err.Error())
+ }
+
+ return result
+}
+
+func (s *RedisSupplier) ReactionDeleteAllWithEmojiName(ctx context.Context, emojiName string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
+ // Ignoring this. It's probably OK to have the emoji slowly expire from Redis.
+ return s.Next().ReactionDeleteAllWithEmojiName(ctx, emojiName, hints...)
+}