From 7118e6f646bd00c42adf55b51ec9725894e6e40b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Oct 2023 23:26:59 +0800 Subject: [PATCH] Fix test --- caches/cache.go | 99 --------- caches/encode.go | 65 ------ caches/leveldb.go | 99 --------- caches/leveldb_test.go | 39 ---- caches/lru.go | 278 -------------------------- caches/lru_test.go | 52 ----- caches/manager.go | 60 ------ caches/memory_store.go | 49 ----- caches/memory_store_test.go | 37 ---- engine.go | 72 +------ engine_group.go | 9 - interface.go | 7 - internal/statements/statement.go | 2 - internal/statements/statement_test.go | 4 +- session.go | 20 -- session_delete.go | 79 -------- session_find.go | 228 +-------------------- session_get.go | 107 ---------- session_insert.go | 27 --- session_iterate.go | 2 +- session_update.go | 7 - tags/parser.go | 26 +-- tags/parser_test.go | 67 ------- tags/tag.go | 20 -- tests/cache_test.go | 183 ----------------- tests/session_delete_test.go | 33 --- tests/session_get_test.go | 8 +- tests/tags_test.go | 24 --- tests/tests.go | 7 +- 29 files changed, 12 insertions(+), 1698 deletions(-) delete mode 100644 caches/cache.go delete mode 100644 caches/encode.go delete mode 100644 caches/leveldb.go delete mode 100644 caches/leveldb_test.go delete mode 100644 caches/lru.go delete mode 100644 caches/lru_test.go delete mode 100644 caches/manager.go delete mode 100644 caches/memory_store.go delete mode 100644 caches/memory_store_test.go delete mode 100644 tests/cache_test.go diff --git a/caches/cache.go b/caches/cache.go deleted file mode 100644 index 9a769450..00000000 --- a/caches/cache.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "bytes" - "encoding/gob" - "errors" - "fmt" - "strings" - "time" - - "xorm.io/xorm/v2/schemas" -) - -const ( - // CacheExpired is default cache expired time - CacheExpired = 60 * time.Minute - // CacheMaxMemory is not use now - CacheMaxMemory = 256 - // CacheGcInterval represents interval time to clear all expired nodes - CacheGcInterval = 10 * time.Minute - // CacheGcMaxRemoved represents max nodes removed when gc - CacheGcMaxRemoved = 20 -) - -// list all the errors -var ( - ErrCacheMiss = errors.New("xorm/cache: key not found") - ErrNotStored = errors.New("xorm/cache: not stored") - // ErrNotExist record does not exist error - ErrNotExist = errors.New("Record does not exist") -) - -// CacheStore is a interface to store cache -type CacheStore interface { - // key is primary key or composite primary key - // value is struct's pointer - // key format : -p--... - Put(key string, value interface{}) error - Get(key string) (interface{}, error) - Del(key string) error -} - -// Cacher is an interface to provide cache -// id format : u--... -type Cacher interface { - GetIds(tableName, sql string) interface{} - GetBean(tableName string, id string) interface{} - PutIds(tableName, sql string, ids interface{}) - PutBean(tableName string, id string, obj interface{}) - DelIds(tableName, sql string) - DelBean(tableName string, id string) - ClearIds(tableName string) - ClearBeans(tableName string) -} - -func encodeIds(ids []schemas.PK) (string, error) { - buf := new(bytes.Buffer) - enc := gob.NewEncoder(buf) - err := enc.Encode(ids) - - return buf.String(), err -} - -func decodeIds(s string) ([]schemas.PK, error) { - pks := make([]schemas.PK, 0) - - dec := gob.NewDecoder(strings.NewReader(s)) - err := dec.Decode(&pks) - - return pks, err -} - -// GetCacheSql returns cacher PKs via SQL -func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]schemas.PK, error) { - bytes := m.GetIds(tableName, GenSqlKey(sql, args)) - if bytes == nil { - return nil, errors.New("Not Exist") - } - return decodeIds(bytes.(string)) -} - -// PutCacheSql puts cacher SQL and PKs -func PutCacheSql(m Cacher, ids []schemas.PK, tableName, sql string, args interface{}) error { - bytes, err := encodeIds(ids) - if err != nil { - return err - } - m.PutIds(tableName, GenSqlKey(sql, args), bytes) - return nil -} - -// GenSqlKey generates cache key -func GenSqlKey(sql string, args interface{}) string { - return fmt.Sprintf("%v-%v", sql, args) -} diff --git a/caches/encode.go b/caches/encode.go deleted file mode 100644 index 8659668c..00000000 --- a/caches/encode.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2020 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "bytes" - "crypto/md5" - "encoding/gob" - "encoding/json" - "fmt" - "io" -) - -// Md5 return md5 hash string -func Md5(str string) string { - m := md5.New() - _, _ = io.WriteString(m, str) - return fmt.Sprintf("%x", m.Sum(nil)) -} - -// Encode Encode data -func Encode(data interface{}) ([]byte, error) { - // return JsonEncode(data) - return GobEncode(data) -} - -// Decode decode data -func Decode(data []byte, to interface{}) error { - // return JsonDecode(data, to) - return GobDecode(data, to) -} - -// GobEncode encode data with gob -func GobEncode(data interface{}) ([]byte, error) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(&data) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// GobDecode decode data with gob -func GobDecode(data []byte, to interface{}) error { - buf := bytes.NewBuffer(data) - dec := gob.NewDecoder(buf) - return dec.Decode(to) -} - -// JsonEncode encode data with json -func JsonEncode(data interface{}) ([]byte, error) { - val, err := json.Marshal(data) - if err != nil { - return nil, err - } - return val, nil -} - -// JsonDecode decode data with json -func JsonDecode(data []byte, to interface{}) error { - return json.Unmarshal(data, to) -} diff --git a/caches/leveldb.go b/caches/leveldb.go deleted file mode 100644 index f2f71d84..00000000 --- a/caches/leveldb.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2020 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "log" - - "github.com/syndtr/goleveldb/leveldb" -) - -// LevelDBStore implements CacheStore provide local machine -type LevelDBStore struct { - store *leveldb.DB - Debug bool - v interface{} -} - -var _ CacheStore = &LevelDBStore{} - -// NewLevelDBStore creates a leveldb store -func NewLevelDBStore(dbfile string) (*LevelDBStore, error) { - db := &LevelDBStore{} - h, err := leveldb.OpenFile(dbfile, nil) - if err != nil { - return nil, err - } - db.store = h - return db, nil -} - -// Put implements CacheStore -func (s *LevelDBStore) Put(key string, value interface{}) error { - val, err := Encode(value) - if err != nil { - if s.Debug { - log.Println("[LevelDB]EncodeErr: ", err, "Key:", key) - } - return err - } - err = s.store.Put([]byte(key), val, nil) - if err != nil { - if s.Debug { - log.Println("[LevelDB]PutErr: ", err, "Key:", key) - } - return err - } - if s.Debug { - log.Println("[LevelDB]Put: ", key) - } - return err -} - -// Get implements CacheStore -func (s *LevelDBStore) Get(key string) (interface{}, error) { - data, err := s.store.Get([]byte(key), nil) - if err != nil { - if s.Debug { - log.Println("[LevelDB]GetErr: ", err, "Key:", key) - } - if err == leveldb.ErrNotFound { - return nil, ErrNotExist - } - return nil, err - } - - err = Decode(data, &s.v) - if err != nil { - if s.Debug { - log.Println("[LevelDB]DecodeErr: ", err, "Key:", key) - } - return nil, err - } - if s.Debug { - log.Println("[LevelDB]Get: ", key, s.v) - } - return s.v, err -} - -// Del implements CacheStore -func (s *LevelDBStore) Del(key string) error { - err := s.store.Delete([]byte(key), nil) - if err != nil { - if s.Debug { - log.Println("[LevelDB]DelErr: ", err, "Key:", key) - } - return err - } - if s.Debug { - log.Println("[LevelDB]Del: ", key) - } - return err -} - -// Close implements CacheStore -func (s *LevelDBStore) Close() { - s.store.Close() -} diff --git a/caches/leveldb_test.go b/caches/leveldb_test.go deleted file mode 100644 index 35981db1..00000000 --- a/caches/leveldb_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2020 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLevelDBStore(t *testing.T) { - store, err := NewLevelDBStore("./level.db") - assert.NoError(t, err) - - var kvs = map[string]interface{}{ - "a": "b", - } - for k, v := range kvs { - assert.NoError(t, store.Put(k, v)) - } - - for k, v := range kvs { - val, err := store.Get(k) - assert.NoError(t, err) - assert.EqualValues(t, v, val) - } - - for k := range kvs { - err := store.Del(k) - assert.NoError(t, err) - } - - for k := range kvs { - _, err := store.Get(k) - assert.EqualValues(t, ErrNotExist, err) - } -} diff --git a/caches/lru.go b/caches/lru.go deleted file mode 100644 index 885f02d6..00000000 --- a/caches/lru.go +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "container/list" - "fmt" - "sync" - "time" -) - -// LRUCacher implments cache object facilities -type LRUCacher struct { - idList *list.List - sqlList *list.List - idIndex map[string]map[string]*list.Element - sqlIndex map[string]map[string]*list.Element - store CacheStore - mutex sync.Mutex - MaxElementSize int - Expired time.Duration - GcInterval time.Duration -} - -// NewLRUCacher creates a cacher -func NewLRUCacher(store CacheStore, maxElementSize int) *LRUCacher { - return NewLRUCacher2(store, 3600*time.Second, maxElementSize) -} - -// NewLRUCacher2 creates a cache include different params -func NewLRUCacher2(store CacheStore, expired time.Duration, maxElementSize int) *LRUCacher { - cacher := &LRUCacher{store: store, idList: list.New(), - sqlList: list.New(), Expired: expired, - GcInterval: CacheGcInterval, MaxElementSize: maxElementSize, - sqlIndex: make(map[string]map[string]*list.Element), - idIndex: make(map[string]map[string]*list.Element), - } - cacher.RunGC() - return cacher -} - -// RunGC run once every m.GcInterval -func (m *LRUCacher) RunGC() { - time.AfterFunc(m.GcInterval, func() { - m.RunGC() - m.GC() - }) -} - -// GC check ids lit and sql list to remove all element expired -func (m *LRUCacher) GC() { - m.mutex.Lock() - defer m.mutex.Unlock() - var removedNum int - for e := m.idList.Front(); e != nil; { - if removedNum <= CacheGcMaxRemoved && - time.Since(e.Value.(*idNode).lastVisit) > m.Expired { - removedNum++ - next := e.Next() - node := e.Value.(*idNode) - m.delBean(node.tbName, node.id) - e = next - } else { - break - } - } - - removedNum = 0 - for e := m.sqlList.Front(); e != nil; { - if removedNum <= CacheGcMaxRemoved && - time.Since(e.Value.(*sqlNode).lastVisit) > m.Expired { - removedNum++ - next := e.Next() - node := e.Value.(*sqlNode) - m.delIds(node.tbName, node.sql) - e = next - } else { - break - } - } -} - -// GetIds returns all bean's ids according to sql and parameter from cache -func (m *LRUCacher) GetIds(tableName, sql string) interface{} { - m.mutex.Lock() - defer m.mutex.Unlock() - if _, ok := m.sqlIndex[tableName]; !ok { - m.sqlIndex[tableName] = make(map[string]*list.Element) - } - if v, err := m.store.Get(sql); err == nil { - if el, ok := m.sqlIndex[tableName][sql]; !ok { - el = m.sqlList.PushBack(newSQLNode(tableName, sql)) - m.sqlIndex[tableName][sql] = el - } else { - lastTime := el.Value.(*sqlNode).lastVisit - // if expired, remove the node and return nil - if time.Since(lastTime) > m.Expired { - m.delIds(tableName, sql) - return nil - } - m.sqlList.MoveToBack(el) - el.Value.(*sqlNode).lastVisit = time.Now() - } - return v - } - - m.delIds(tableName, sql) - return nil -} - -// GetBean returns bean according tableName and id from cache -func (m *LRUCacher) GetBean(tableName string, id string) interface{} { - m.mutex.Lock() - defer m.mutex.Unlock() - if _, ok := m.idIndex[tableName]; !ok { - m.idIndex[tableName] = make(map[string]*list.Element) - } - tid := genID(tableName, id) - if v, err := m.store.Get(tid); err == nil { - if el, ok := m.idIndex[tableName][id]; ok { - lastTime := el.Value.(*idNode).lastVisit - // if expired, remove the node and return nil - if time.Since(lastTime) > m.Expired { - m.delBean(tableName, id) - return nil - } - m.idList.MoveToBack(el) - el.Value.(*idNode).lastVisit = time.Now() - } else { - el = m.idList.PushBack(newIDNode(tableName, id)) - m.idIndex[tableName][id] = el - } - return v - } - - // store bean is not exist, then remove memory's index - m.delBean(tableName, id) - return nil -} - -// clearIds clears all sql-ids mapping on table tableName from cache -func (m *LRUCacher) clearIds(tableName string) { - if tis, ok := m.sqlIndex[tableName]; ok { - for sql, v := range tis { - m.sqlList.Remove(v) - _ = m.store.Del(sql) - } - } - m.sqlIndex[tableName] = make(map[string]*list.Element) -} - -// ClearIds clears all sql-ids mapping on table tableName from cache -func (m *LRUCacher) ClearIds(tableName string) { - m.mutex.Lock() - m.clearIds(tableName) - m.mutex.Unlock() -} - -func (m *LRUCacher) clearBeans(tableName string) { - if tis, ok := m.idIndex[tableName]; ok { - for id, v := range tis { - m.idList.Remove(v) - tid := genID(tableName, id) - _ = m.store.Del(tid) - } - } - m.idIndex[tableName] = make(map[string]*list.Element) -} - -// ClearBeans clears all beans in some table -func (m *LRUCacher) ClearBeans(tableName string) { - m.mutex.Lock() - m.clearBeans(tableName) - m.mutex.Unlock() -} - -// PutIds pus ids into table -func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { - m.mutex.Lock() - if _, ok := m.sqlIndex[tableName]; !ok { - m.sqlIndex[tableName] = make(map[string]*list.Element) - } - if el, ok := m.sqlIndex[tableName][sql]; !ok { - el = m.sqlList.PushBack(newSQLNode(tableName, sql)) - m.sqlIndex[tableName][sql] = el - } else { - el.Value.(*sqlNode).lastVisit = time.Now() - } - _ = m.store.Put(sql, ids) - if m.sqlList.Len() > m.MaxElementSize { - e := m.sqlList.Front() - node := e.Value.(*sqlNode) - m.delIds(node.tbName, node.sql) - } - m.mutex.Unlock() -} - -// PutBean puts beans into table -func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { - m.mutex.Lock() - var el *list.Element - var ok bool - - if el, ok = m.idIndex[tableName][id]; !ok { - el = m.idList.PushBack(newIDNode(tableName, id)) - m.idIndex[tableName][id] = el - } else { - el.Value.(*idNode).lastVisit = time.Now() - } - - _ = m.store.Put(genID(tableName, id), obj) - if m.idList.Len() > m.MaxElementSize { - e := m.idList.Front() - node := e.Value.(*idNode) - m.delBean(node.tbName, node.id) - } - m.mutex.Unlock() -} - -func (m *LRUCacher) delIds(tableName, sql string) { - if _, ok := m.sqlIndex[tableName]; ok { - if el, ok := m.sqlIndex[tableName][sql]; ok { - delete(m.sqlIndex[tableName], sql) - m.sqlList.Remove(el) - } - } - _ = m.store.Del(sql) -} - -// DelIds deletes ids -func (m *LRUCacher) DelIds(tableName, sql string) { - m.mutex.Lock() - m.delIds(tableName, sql) - m.mutex.Unlock() -} - -func (m *LRUCacher) delBean(tableName string, id string) { - tid := genID(tableName, id) - if el, ok := m.idIndex[tableName][id]; ok { - delete(m.idIndex[tableName], id) - m.idList.Remove(el) - m.clearIds(tableName) - } - _ = m.store.Del(tid) -} - -// DelBean deletes beans in some table -func (m *LRUCacher) DelBean(tableName string, id string) { - m.mutex.Lock() - m.delBean(tableName, id) - m.mutex.Unlock() -} - -type idNode struct { - tbName string - id string - lastVisit time.Time -} - -type sqlNode struct { - tbName string - sql string - lastVisit time.Time -} - -func genID(prefix string, id string) string { - return fmt.Sprintf("%s-%s", prefix, id) -} - -func newIDNode(tbName string, id string) *idNode { - return &idNode{tbName, id, time.Now()} -} - -func newSQLNode(tbName, sql string) *sqlNode { - return &sqlNode{tbName, sql, time.Now()} -} diff --git a/caches/lru_test.go b/caches/lru_test.go deleted file mode 100644 index beb3bb7b..00000000 --- a/caches/lru_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "xorm.io/xorm/v2/schemas" -) - -func TestLRUCache(t *testing.T) { - type CacheObject1 struct { - Id int64 - } - - store := NewMemoryStore() - cacher := NewLRUCacher(store, 10000) - - tableName := "cache_object1" - pks := []schemas.PK{ - {1}, - {2}, - } - - for _, pk := range pks { - sid, err := pk.ToString() - assert.NoError(t, err) - - cacher.PutIds(tableName, "select * from cache_object1", sid) - ids := cacher.GetIds(tableName, "select * from cache_object1") - assert.EqualValues(t, sid, ids) - - cacher.ClearIds(tableName) - ids2 := cacher.GetIds(tableName, "select * from cache_object1") - assert.Nil(t, ids2) - - obj2 := cacher.GetBean(tableName, sid) - assert.Nil(t, obj2) - - obj := new(CacheObject1) - cacher.PutBean(tableName, sid, obj) - obj3 := cacher.GetBean(tableName, sid) - assert.EqualValues(t, obj, obj3) - - cacher.DelBean(tableName, sid) - obj4 := cacher.GetBean(tableName, sid) - assert.Nil(t, obj4) - } -} diff --git a/caches/manager.go b/caches/manager.go deleted file mode 100644 index 89a14106..00000000 --- a/caches/manager.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2020 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import "sync" - -// Manager represents a cache manager -type Manager struct { - cacher Cacher - disableGlobalCache bool - - cachers map[string]Cacher - cacherLock sync.RWMutex -} - -// NewManager creates a cache manager -func NewManager() *Manager { - return &Manager{ - cachers: make(map[string]Cacher), - } -} - -// SetDisableGlobalCache disable global cache or not -func (mgr *Manager) SetDisableGlobalCache(disable bool) { - if mgr.disableGlobalCache != disable { - mgr.disableGlobalCache = disable - } -} - -// SetCacher set cacher of table -func (mgr *Manager) SetCacher(tableName string, cacher Cacher) { - mgr.cacherLock.Lock() - mgr.cachers[tableName] = cacher - mgr.cacherLock.Unlock() -} - -// GetCacher returns a cache of a table -func (mgr *Manager) GetCacher(tableName string) Cacher { - var cacher Cacher - var ok bool - mgr.cacherLock.RLock() - cacher, ok = mgr.cachers[tableName] - mgr.cacherLock.RUnlock() - if !ok && !mgr.disableGlobalCache { - cacher = mgr.cacher - } - return cacher -} - -// SetDefaultCacher set the default cacher. Xorm's default not enable cacher. -func (mgr *Manager) SetDefaultCacher(cacher Cacher) { - mgr.cacher = cacher -} - -// GetDefaultCacher returns the default cacher -func (mgr *Manager) GetDefaultCacher() Cacher { - return mgr.cacher -} diff --git a/caches/memory_store.go b/caches/memory_store.go deleted file mode 100644 index f16254d8..00000000 --- a/caches/memory_store.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "sync" -) - -var _ CacheStore = NewMemoryStore() - -// MemoryStore represents in-memory store -type MemoryStore struct { - store map[interface{}]interface{} - mutex sync.RWMutex -} - -// NewMemoryStore creates a new store in memory -func NewMemoryStore() *MemoryStore { - return &MemoryStore{store: make(map[interface{}]interface{})} -} - -// Put puts object into store -func (s *MemoryStore) Put(key string, value interface{}) error { - s.mutex.Lock() - defer s.mutex.Unlock() - s.store[key] = value - return nil -} - -// Get gets object from store -func (s *MemoryStore) Get(key string) (interface{}, error) { - s.mutex.RLock() - defer s.mutex.RUnlock() - if v, ok := s.store[key]; ok { - return v, nil - } - - return nil, ErrNotExist -} - -// Del deletes object -func (s *MemoryStore) Del(key string) error { - s.mutex.Lock() - defer s.mutex.Unlock() - delete(s.store, key) - return nil -} diff --git a/caches/memory_store_test.go b/caches/memory_store_test.go deleted file mode 100644 index 12db4ea7..00000000 --- a/caches/memory_store_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package caches - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestMemoryStore(t *testing.T) { - store := NewMemoryStore() - var kvs = map[string]interface{}{ - "a": "b", - } - for k, v := range kvs { - assert.NoError(t, store.Put(k, v)) - } - - for k, v := range kvs { - val, err := store.Get(k) - assert.NoError(t, err) - assert.EqualValues(t, v, val) - } - - for k := range kvs { - err := store.Del(k) - assert.NoError(t, err) - } - - for k := range kvs { - _, err := store.Get(k) - assert.EqualValues(t, ErrNotExist, err) - } -} diff --git a/engine.go b/engine.go index d0894d06..eaf6b8e3 100644 --- a/engine.go +++ b/engine.go @@ -17,7 +17,6 @@ import ( "strings" "time" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/contexts" "xorm.io/xorm/v2/core" "xorm.io/xorm/v2/dialects" @@ -31,7 +30,6 @@ import ( // Engine is the major struct of xorm, it means a database manager. // Commonly, an application only need one engine type Engine struct { - cacherMgr *caches.Manager defaultContext context.Context dialect dialects.Dialect driver dialects.Driver @@ -66,16 +64,14 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) { } func newEngine(driverName, dataSourceName string, dialect dialects.Dialect, db *core.DB) (*Engine, error) { - cacherMgr := caches.NewManager() mapper := names.NewCacheMapper(new(names.SnakeMapper)) - tagParser := tags.NewParser("xorm", dialect, mapper, mapper, cacherMgr) + tagParser := tags.NewParser("xorm", dialect, mapper, mapper) engine := &Engine{ dialect: dialect, driver: dialects.QueryDriver(driverName), TZLocation: time.Local, defaultContext: context.Background(), - cacherMgr: cacherMgr, tagParser: tagParser, driverName: driverName, dataSourceName: dataSourceName, @@ -129,16 +125,6 @@ func (engine *Engine) EnableSessionID(enable bool) { engine.logSessionID = enable } -// SetCacher sets cacher for the table -func (engine *Engine) SetCacher(tableName string, cacher caches.Cacher) { - engine.cacherMgr.SetCacher(tableName, cacher) -} - -// GetCacher returns the cachher of the special table -func (engine *Engine) GetCacher(tableName string) caches.Cacher { - return engine.cacherMgr.GetCacher(tableName) -} - // SetQuotePolicy sets the special quote policy func (engine *Engine) SetQuotePolicy(quotePolicy dialects.QuotePolicy) { engine.dialect.SetQuotePolicy(quotePolicy) @@ -182,11 +168,6 @@ func (engine *Engine) SetLogLevel(level log.LogLevel) { engine.logger.SetLevel(level) } -// SetDisableGlobalCache disable global cache or not -func (engine *Engine) SetDisableGlobalCache(disable bool) { - engine.cacherMgr.SetDisableGlobalCache(disable) -} - // DriverName return the current sql driver's name func (engine *Engine) DriverName() string { return engine.driverName @@ -269,24 +250,6 @@ func (engine *Engine) SetMaxIdleConns(conns int) { engine.DB().SetMaxIdleConns(conns) } -// SetDefaultCacher set the default cacher. Xorm's default not enable cacher. -func (engine *Engine) SetDefaultCacher(cacher caches.Cacher) { - engine.cacherMgr.SetDefaultCacher(cacher) -} - -// GetDefaultCacher returns the default cacher -func (engine *Engine) GetDefaultCacher() caches.Cacher { - return engine.cacherMgr.GetDefaultCacher() -} - -// NoCache If you has set default cacher, and you want temporilly stop use cache, -// you can use NoCache() -func (engine *Engine) NoCache() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.NoCache() -} - // NoCascade If you do not want to auto cascade load object func (engine *Engine) NoCascade() *Session { session := engine.NewSession() @@ -294,12 +257,6 @@ func (engine *Engine) NoCascade() *Session { return session.NoCascade() } -// MapCacher Set a table use a special cacher -func (engine *Engine) MapCacher(bean interface{}, cacher caches.Cacher) error { - engine.SetCacher(dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean, true), cacher) - return nil -} - // NewDB provides an interface to operate database directly func (engine *Engine) NewDB() (*core.DB, error) { return core.Open(engine.driverName, engine.dataSourceName) @@ -481,8 +438,7 @@ func (engine *Engine) dumpTables(ctx context.Context, tables []*schemas.Table, w return err } } - cacherMgr := caches.NewManager() - dstTableCache := tags.NewParser("xorm", dstDialect, engine.GetTableMapper(), engine.GetColumnMapper(), cacherMgr) + dstTableCache := tags.NewParser("xorm", dstDialect, engine.GetTableMapper(), engine.GetColumnMapper()) _, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm %s, from %s to %s*/\n\n", time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.URI().DBType, dstDialect.URI().DBType)) @@ -1091,30 +1047,6 @@ func (engine *Engine) CreateUniques(bean interface{}) error { return session.CreateUniques(bean) } -// ClearCacheBean if enabled cache, clear the cache bean -func (engine *Engine) ClearCacheBean(bean interface{}, id string) error { - tableName := dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean) - cacher := engine.GetCacher(tableName) - if cacher != nil { - cacher.ClearIds(tableName) - cacher.DelBean(tableName, id) - } - return nil -} - -// ClearCache if enabled cache, clear some tables' cache -func (engine *Engine) ClearCache(beans ...interface{}) error { - for _, bean := range beans { - tableName := dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean) - cacher := engine.GetCacher(tableName) - if cacher != nil { - cacher.ClearIds(tableName) - cacher.ClearBeans(tableName) - } - } - return nil -} - // UnMapType remove table from tables cache func (engine *Engine) UnMapType(t reflect.Type) { engine.tagParser.ClearCacheTable(t) diff --git a/engine_group.go b/engine_group.go index d718c556..41855253 100644 --- a/engine_group.go +++ b/engine_group.go @@ -8,7 +8,6 @@ import ( "context" "time" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/contexts" "xorm.io/xorm/v2/dialects" "xorm.io/xorm/v2/log" @@ -128,14 +127,6 @@ func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) { } } -// SetDefaultCacher set the default cacher -func (eg *EngineGroup) SetDefaultCacher(cacher caches.Cacher) { - eg.Engine.SetDefaultCacher(cacher) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].SetDefaultCacher(cacher) - } -} - // SetLogger set the new logger func (eg *EngineGroup) SetLogger(logger interface{}) { eg.Engine.SetLogger(logger) diff --git a/interface.go b/interface.go index 01329b5f..2f761169 100644 --- a/interface.go +++ b/interface.go @@ -10,7 +10,6 @@ import ( "reflect" "time" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/contexts" "xorm.io/xorm/v2/dialects" "xorm.io/xorm/v2/log" @@ -81,7 +80,6 @@ type EngineInterface interface { Before(func(interface{})) *Session Charset(charset string) *Session - ClearCache(...interface{}) error Context(context.Context) *Session CreateTables(...interface{}) error DBMetas() ([]*schemas.Table, error) @@ -90,23 +88,18 @@ type EngineInterface interface { DriverName() string DropTables(...interface{}) error DumpAllToFile(fp string, tp ...schemas.DBType) error - GetCacher(string) caches.Cacher GetColumnMapper() names.Mapper - GetDefaultCacher() caches.Cacher GetTableMapper() names.Mapper GetTZDatabase() *time.Location GetTZLocation() *time.Location ImportFile(fp string) ([]sql.Result, error) - MapCacher(interface{}, caches.Cacher) error NewSession() *Session NoAutoTime() *Session Prepare() *Session Quote(string) string - SetCacher(string, caches.Cacher) SetConnMaxLifetime(time.Duration) SetColumnMapper(names.Mapper) SetTagIdentifier(string) - SetDefaultCacher(caches.Cacher) SetLogger(logger interface{}) SetLogLevel(log.LogLevel) SetMapper(names.Mapper) diff --git a/internal/statements/statement.go b/internal/statements/statement.go index cce33701..7bb8f342 100644 --- a/internal/statements/statement.go +++ b/internal/statements/statement.go @@ -64,7 +64,6 @@ type Statement struct { UseAutoJoin bool StoreEngine string Charset string - UseCache bool UseAutoTime bool NoAutoCondition bool IsDistinct bool @@ -138,7 +137,6 @@ func (statement *Statement) Reset() { statement.idParam = nil statement.RawSQL = "" statement.RawParams = make([]interface{}, 0) - statement.UseCache = true statement.UseAutoTime = true statement.NoAutoCondition = false statement.IsDistinct = false diff --git a/internal/statements/statement_test.go b/internal/statements/statement_test.go index 7fba9e3f..9526ddeb 100644 --- a/internal/statements/statement_test.go +++ b/internal/statements/statement_test.go @@ -12,7 +12,7 @@ import ( "time" "github.com/stretchr/testify/assert" - "xorm.io/xorm/v2/caches" + "xorm.io/xorm/v2/dialects" "xorm.io/xorm/v2/names" "xorm.io/xorm/v2/schemas" @@ -33,7 +33,7 @@ func TestMain(m *testing.M) { panic("unknow dialect") } - tagParser = tags.NewParser("xorm", dialect, names.SnakeMapper{}, names.SnakeMapper{}, caches.NewManager()) + tagParser = tags.NewParser("xorm", dialect, names.SnakeMapper{}, names.SnakeMapper{}) if tagParser == nil { panic("tags parser is nil") } diff --git a/session.go b/session.go index f25ce90d..4b64d1aa 100644 --- a/session.go +++ b/session.go @@ -321,13 +321,6 @@ func (session *Session) MustLogSQL(logs ...bool) *Session { return session } -// NoCache ask this session do not retrieve data from cache system and -// get data from database directly. -func (session *Session) NoCache() *Session { - session.statement.UseCache = false - return session -} - // Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN func (session *Session) Join(joinOperator string, tablename interface{}, condition interface{}, args ...interface{}) *Session { session.statement.Join(joinOperator, tablename, condition, args...) @@ -351,19 +344,6 @@ func (session *Session) DB() *core.DB { return session.db() } -func (session *Session) canCache() bool { - if session.statement.RefTable == nil || - session.statement.NeedTableName() || - session.statement.RawSQL != "" || - !session.statement.UseCache || - session.statement.IsForUpdate || - session.tx != nil || - len(session.statement.SelectStr) > 0 { - return false - } - return true -} - func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) { crc := crc32.ChecksumIEEE([]byte(sqlStr)) // TODO try hash(sqlStr+len(sqlStr)) diff --git a/session_delete.go b/session_delete.go index ab94dd55..59e4b1c4 100644 --- a/session_delete.go +++ b/session_delete.go @@ -6,83 +6,13 @@ package xorm import ( "errors" - "strconv" "xorm.io/builder" - "xorm.io/xorm/v2/caches" - "xorm.io/xorm/v2/schemas" ) // ErrNeedDeletedCond delete needs less one condition error var ErrNeedDeletedCond = errors.New("Delete action needs at least one condition") -func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error { - if table == nil || - session.tx != nil { - return ErrCacheFailed - } - - for _, filter := range session.engine.dialect.Filters() { - sqlStr = filter.Do(session.ctx, sqlStr) - } - - newsql := session.statement.ConvertIDSQL(sqlStr) - if newsql == "" { - return ErrCacheFailed - } - - cacher := session.engine.cacherMgr.GetCacher(tableName) - pkColumns := table.PKColumns() - ids, err := caches.GetCacheSql(cacher, tableName, newsql, args) - if err != nil { - rows, err := session.queryRows(newsql, args...) - if err != nil { - return err - } - defer rows.Close() - - resultsSlice, err := session.engine.ScanStringMaps(rows) - if err != nil { - return err - } - ids = make([]schemas.PK, 0) - if len(resultsSlice) > 0 { - for _, data := range resultsSlice { - var id int64 - var pk schemas.PK = make([]interface{}, 0) - for _, col := range pkColumns { - if v, ok := data[col.Name]; !ok { - return errors.New("no id") - } else if col.SQLType.IsText() { - pk = append(pk, v) - } else if col.SQLType.IsNumeric() { - id, err = strconv.ParseInt(v, 10, 64) - if err != nil { - return err - } - pk = append(pk, id) - } else { - return errors.New("not supported primary key type") - } - } - ids = append(ids, pk) - } - } - } - - for _, id := range ids { - session.engine.logger.Debugf("[cache] delete cache obj: %v, %v", tableName, id) - sid, err := id.ToString() - if err != nil { - return err - } - cacher.DelBean(tableName, sid) - } - session.engine.logger.Debugf("[cache] clear cache table: %v", tableName) - cacher.ClearIds(tableName) - return nil -} - // Delete records, bean's non-empty fields are conditions // At least one condition must be set. func (session *Session) Delete(beans ...interface{}) (int64, error) { @@ -130,7 +60,6 @@ func (session *Session) delete(beans []interface{}, mustHaveConditions bool) (in return 0, ErrNeedDeletedCond } - tableNameNoQuote := session.statement.TableName() table := session.statement.RefTable realSQLWriter := builder.NewWriter() @@ -154,14 +83,6 @@ func (session *Session) delete(beans []interface{}, mustHaveConditions bool) (in }) } - argsForCache := make([]interface{}, 0, len(deleteSQLWriter.Args())*2) - copy(argsForCache, deleteSQLWriter.Args()) - argsForCache = append(deleteSQLWriter.Args(), argsForCache...) - - if cacher := session.engine.GetCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache { - _ = session.cacheDelete(table, tableNameNoQuote, deleteSQLWriter.String(), argsForCache...) - } - session.statement.RefTable = table res, err := session.exec(realSQLWriter.String(), realSQLWriter.Args()...) if err != nil { diff --git a/session_find.go b/session_find.go index a0723a40..e1f61426 100644 --- a/session_find.go +++ b/session_find.go @@ -11,9 +11,8 @@ import ( "strings" "xorm.io/builder" - "xorm.io/xorm/v2/caches" + "xorm.io/xorm/v2/convert" - "xorm.io/xorm/v2/internal/statements" "xorm.io/xorm/v2/internal/utils" "xorm.io/xorm/v2/schemas" ) @@ -148,18 +147,6 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) return err } - if session.statement.ColumnMap.IsEmpty() && session.canCache() { - if cacher := session.engine.GetCacher(session.statement.TableName()); cacher != nil && - !session.statement.IsDistinct && - !session.statement.GetUnscoped() { - err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...) - if err != ErrCacheFailed { - return err - } - session.engine.logger.Warnf("Cache Find Failed") - } - } - return session.noCacheFind(table, sliceValue, sqlStr, args...) } @@ -331,216 +318,3 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect } return rows.Err() } - -func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) { - if !session.canCache() || - utils.IndexNoCase(sqlStr, "having") != -1 || - utils.IndexNoCase(sqlStr, "group by") != -1 { - return ErrCacheFailed - } - - tableName := session.statement.TableName() - cacher := session.engine.cacherMgr.GetCacher(tableName) - if cacher == nil { - return nil - } - - for _, filter := range session.engine.dialect.Filters() { - sqlStr = filter.Do(session.ctx, sqlStr) - } - - newsql := session.statement.ConvertIDSQL(sqlStr) - if newsql == "" { - return ErrCacheFailed - } - - table := session.statement.RefTable - ids, err := caches.GetCacheSql(cacher, tableName, newsql, args) - if err != nil { - rows, err := session.queryRows(newsql, args...) - if err != nil { - return err - } - defer rows.Close() - - var i int - ids = make([]schemas.PK, 0) - for rows.Next() { - i++ - if i > 500 { - session.engine.logger.Debugf("[cacheFind] ids length > 500, no cache") - return ErrCacheFailed - } - res := make([]string, len(table.PrimaryKeys)) - err = rows.ScanSlice(&res) - if err != nil { - return err - } - var pk schemas.PK = make([]interface{}, len(table.PrimaryKeys)) - for i, col := range table.PKColumns() { - pk[i], err = col.ConvertID(res[i]) - if err != nil { - return err - } - } - - ids = append(ids, pk) - } - if rows.Err() != nil { - return rows.Err() - } - - session.engine.logger.Debugf("[cache] cache sql: %v, %v, %v, %v, %v", ids, tableName, sqlStr, newsql, args) - err = caches.PutCacheSql(cacher, ids, tableName, newsql, args) - if err != nil { - return err - } - } else { - session.engine.logger.Debugf("[cache] cache hit sql: %v, %v, %v, %v", tableName, sqlStr, newsql, args) - } - - sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) - - ididxes := make(map[string]int) - var ides []schemas.PK - temps := make([]interface{}, len(ids)) - - for idx, id := range ids { - sid, err := id.ToString() - if err != nil { - return err - } - bean := cacher.GetBean(tableName, sid) - - // fix issue #894 - isHit := func() (ht bool) { - if bean == nil { - ht = false - return - } - ckb := reflect.ValueOf(bean).Elem().Type() - ht = ckb == t - if !ht && t.Kind() == reflect.Ptr { - ht = t.Elem() == ckb - } - return - } - if !isHit() { - ides = append(ides, id) - ididxes[sid] = idx - } else { - session.engine.logger.Debugf("[cache] cache hit bean: %v, %v, %v", tableName, id, bean) - - pk, err := table.IDOfV(reflect.ValueOf(bean)) - if err != nil { - return err - } - - xid, err := pk.ToString() - if err != nil { - return err - } - - if sid != xid { - session.engine.logger.Errorf("[cache] error cache: %v, %v, %v", xid, sid, bean) - return ErrCacheFailed - } - temps[idx] = bean - } - } - - if len(ides) > 0 { - slices := reflect.New(reflect.SliceOf(t)) - beans := slices.Interface() - - statement := session.statement - session.statement = statements.NewStatement( - session.engine.dialect, - session.engine.tagParser, - session.engine.DatabaseTZ, - ) - if len(table.PrimaryKeys) == 1 { - ff := make([]interface{}, 0, len(ides)) - for _, ie := range ides { - ff = append(ff, ie[0]) - } - - session.In("`"+table.PrimaryKeys[0]+"`", ff...) - } else { - for _, ie := range ides { - cond := builder.NewCond() - for i, name := range table.PrimaryKeys { - cond = cond.And(builder.Eq{"`" + name + "`": ie[i]}) - } - session.Or(cond) - } - } - - err = session.NoCache().Table(tableName).find(beans) - if err != nil { - return err - } - session.statement = statement - - vs := reflect.Indirect(reflect.ValueOf(beans)) - for i := 0; i < vs.Len(); i++ { - rv := vs.Index(i) - if rv.Kind() != reflect.Ptr { - rv = rv.Addr() - } - id, err := table.IDOfV(rv) - if err != nil { - return err - } - sid, err := id.ToString() - if err != nil { - return err - } - - bean := rv.Interface() - temps[ididxes[sid]] = bean - session.engine.logger.Debugf("[cache] cache bean: %v, %v, %v, %v", tableName, id, bean, temps) - cacher.PutBean(tableName, sid, bean) - } - } - - for j := 0; j < len(temps); j++ { - bean := temps[j] - if bean == nil { - session.engine.logger.Warnf("[cache] cache no hit: %v, %v, %v", tableName, ids[j], temps) - // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead - continue - } - if sliceValue.Kind() == reflect.Slice { - if t.Kind() == reflect.Ptr { - sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean))) - } else { - sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean)))) - } - } else if sliceValue.Kind() == reflect.Map { - key := ids[j] - keyType := sliceValue.Type().Key() - keyValue := reflect.New(keyType) - var ikey interface{} - if len(key) == 1 { - if err := convert.AssignValue(keyValue, key[0]); err != nil { - return err - } - ikey = keyValue.Elem().Interface() - } else { - if keyType.Kind() != reflect.Slice { - return errors.New("table have multiple primary keys, key is not schemas.PK or slice") - } - ikey = key - } - - if t.Kind() == reflect.Ptr { - sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean)) - } else { - sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean))) - } - } - } - - return nil -} diff --git a/session_get.go b/session_get.go index ca087ee8..20c441f3 100644 --- a/session_get.go +++ b/session_get.go @@ -10,10 +10,8 @@ import ( "fmt" "math/big" "reflect" - "strconv" "time" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/convert" "xorm.io/xorm/v2/core" "xorm.io/xorm/v2/internal/utils" @@ -90,17 +88,6 @@ func (session *Session) get(beans ...interface{}) (bool, error) { } table := session.statement.RefTable - - if session.statement.ColumnMap.IsEmpty() && session.canCache() && isStruct { - if cacher := session.engine.GetCacher(session.statement.TableName()); cacher != nil && - !session.statement.GetUnscoped() { - has, err := session.cacheGet(beans[0], sqlStr, args...) - if err != ErrCacheFailed { - return has, err - } - } - } - context := session.statement.Context if context != nil && isStruct { res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args)) @@ -270,97 +257,3 @@ func (session *Session) getMap(rows *core.Rows, types []*sql.ColumnType, fields return fmt.Errorf("unspoorted map type: %t", t) } } - -func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) { - // if has no reftable, then don't use cache currently - if !session.canCache() { - return false, ErrCacheFailed - } - - for _, filter := range session.engine.dialect.Filters() { - sqlStr = filter.Do(session.ctx, sqlStr) - } - newsql := session.statement.ConvertIDSQL(sqlStr) - if newsql == "" { - return false, ErrCacheFailed - } - - tableName := session.statement.TableName() - cacher := session.engine.cacherMgr.GetCacher(tableName) - - session.engine.logger.Debugf("[cache] Get SQL: %s, %v", newsql, args) - table := session.statement.RefTable - ids, err := caches.GetCacheSql(cacher, tableName, newsql, args) - if err != nil { - res := make([]string, len(table.PrimaryKeys)) - rows, err := session.NoCache().queryRows(newsql, args...) - if err != nil { - return false, err - } - defer rows.Close() - - if rows.Next() { - err = rows.ScanSlice(&res) - if err != nil { - return true, err - } - } else { - if rows.Err() != nil { - return false, rows.Err() - } - return false, ErrCacheFailed - } - - var pk schemas.PK = make([]interface{}, len(table.PrimaryKeys)) - for i, col := range table.PKColumns() { - if col.SQLType.IsText() { - pk[i] = res[i] - } else if col.SQLType.IsNumeric() { - n, err := strconv.ParseInt(res[i], 10, 64) - if err != nil { - return false, err - } - pk[i] = n - } else { - return false, errors.New("unsupported") - } - } - - ids = []schemas.PK{pk} - session.engine.logger.Debugf("[cache] cache ids: %s, %v", newsql, ids) - err = caches.PutCacheSql(cacher, ids, tableName, newsql, args) - if err != nil { - return false, err - } - } else { - session.engine.logger.Debugf("[cache] cache hit: %s, %v", newsql, ids) - } - - if len(ids) > 0 { - structValue := reflect.Indirect(reflect.ValueOf(bean)) - id := ids[0] - session.engine.logger.Debugf("[cache] get bean: %s, %v", tableName, id) - sid, err := id.ToString() - if err != nil { - return false, err - } - cacheBean := cacher.GetBean(tableName, sid) - if cacheBean == nil { - cacheBean = bean - has, err = session.nocacheGet(reflect.Struct, table, []interface{}{cacheBean}, sqlStr, args...) - if err != nil || !has { - return has, err - } - - session.engine.logger.Debugf("[cache] cache bean: %s, %v, %v", tableName, id, cacheBean) - cacher.PutBean(tableName, sid, cacheBean) - } else { - session.engine.logger.Debugf("[cache] cache hit: %s, %v, %v", tableName, id, cacheBean) - has = true - } - structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean))) - - return has, nil - } - return false, nil -} diff --git a/session_insert.go b/session_insert.go index ae19d366..3a3b12bf 100644 --- a/session_insert.go +++ b/session_insert.go @@ -197,8 +197,6 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e return 0, err } - _ = session.cacheInsert(tableName) - lenAfterClosures := len(session.afterClosures) for i := 0; i < size; i++ { elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface() @@ -354,8 +352,6 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) { defer handleAfterInsertProcessorFunc(bean) - _ = session.cacheInsert(tableName) - if table.Version != "" && session.statement.CheckVersion { verValue, err := table.VersionColumn().ValueOf(bean) if err != nil { @@ -384,8 +380,6 @@ func (session *Session) insertStruct(bean interface{}) (int64, error) { defer handleAfterInsertProcessorFunc(bean) - _ = session.cacheInsert(tableName) - if table.Version != "" && session.statement.CheckVersion { verValue, err := table.VersionColumn().ValueOf(bean) if err != nil { @@ -433,19 +427,6 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) { return session.insertStruct(bean) } -func (session *Session) cacheInsert(table string) error { - if !session.statement.UseCache { - return nil - } - cacher := session.engine.cacherMgr.GetCacher(table) - if cacher == nil { - return nil - } - session.engine.logger.Debugf("[cache] clear SQL: %v", table) - cacher.ClearIds(table) - return nil -} - // genInsertColumns generates insert needed columns func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) { table := session.statement.RefTable @@ -655,10 +636,6 @@ func (session *Session) insertMap(columns []string, args []interface{}) (int64, } sql = session.engine.dialect.Quoter().Replace(sql) - if err := session.cacheInsert(tableName); err != nil { - return 0, err - } - res, err := session.exec(sql, args...) if err != nil { return 0, err @@ -682,10 +659,6 @@ func (session *Session) insertMultipleMap(columns []string, argss [][]interface{ } sql = session.engine.dialect.Quoter().Replace(sql) - if err := session.cacheInsert(tableName); err != nil { - return 0, err - } - res, err := session.exec(sql, args...) if err != nil { return 0, err diff --git a/session_iterate.go b/session_iterate.go index 7786f381..d03dcd99 100644 --- a/session_iterate.go +++ b/session_iterate.go @@ -80,7 +80,7 @@ func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { for bufferSize > 0 { slice := reflect.New(sliceType) - if err := session.NoCache().Limit(bufferSize, start).find(slice.Interface(), bean); err != nil { + if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil { return err } diff --git a/session_update.go b/session_update.go index e4fdbea3..12dcc5d1 100644 --- a/session_update.go +++ b/session_update.go @@ -191,7 +191,6 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 } tableName := session.statement.TableName() // table name must been get before exec because statement will be reset - useCache := session.statement.UseCache res, err := session.exec(updateWriter.String(), updateWriter.Args()...) if err != nil { @@ -202,12 +201,6 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 } } - if cacher := session.engine.GetCacher(tableName); cacher != nil && useCache { - session.engine.logger.Debugf("[cache] clear table: %v", tableName) - cacher.ClearIds(tableName) - cacher.ClearBeans(tableName) - } - // handle after update processors if session.isAutoCommit { for _, closure := range session.afterClosures { diff --git a/tags/parser.go b/tags/parser.go index f25aa64b..1e787c00 100644 --- a/tags/parser.go +++ b/tags/parser.go @@ -5,16 +5,13 @@ package tags import ( - "encoding/gob" "errors" "fmt" "reflect" "strings" "sync" - "time" "unicode" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/convert" "xorm.io/xorm/v2/dialects" "xorm.io/xorm/v2/names" @@ -44,19 +41,17 @@ type Parser struct { columnMapper names.Mapper tableMapper names.Mapper handlers map[string]Handler - cacherMgr *caches.Manager tableCache sync.Map // map[reflect.Type]*schemas.Table } // NewParser creates a tag parser -func NewParser(identifier string, dialect dialects.Dialect, tableMapper, columnMapper names.Mapper, cacherMgr *caches.Manager) *Parser { +func NewParser(identifier string, dialect dialects.Dialect, tableMapper, columnMapper names.Mapper) *Parser { return &Parser{ identifier: identifier, dialect: dialect, tableMapper: tableMapper, columnMapper: columnMapper, handlers: defaultTagHandlers, - cacherMgr: cacherMgr, } } @@ -103,14 +98,6 @@ func (parser *Parser) ParseWithCache(v reflect.Value) (*schemas.Table, error) { parser.tableCache.Store(t, table) - if parser.cacherMgr.GetDefaultCacher() != nil { - if v.CanAddr() { - gob.Register(v.Addr().Interface()) - } else { - gob.Register(v.Interface()) - } - } - return table, nil } @@ -236,17 +223,6 @@ func (parser *Parser) parseFieldWithTags(table *schemas.Table, fieldIndex int, f col.Name = ctx.tag.name } } - - if ctx.hasCacheTag { - if parser.cacherMgr.GetDefaultCacher() != nil { - parser.cacherMgr.SetCacher(table.Name, parser.cacherMgr.GetDefaultCacher()) - } else { - parser.cacherMgr.SetCacher(table.Name, caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000)) - } - } - if ctx.hasNoCacheTag { - parser.cacherMgr.SetCacher(table.Name, nil) - } } if col.SQLType.Name == "" { diff --git a/tags/parser_test.go b/tags/parser_test.go index cb9d8368..7a8475af 100644 --- a/tags/parser_test.go +++ b/tags/parser_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/dialects" "xorm.io/xorm/v2/names" "xorm.io/xorm/v2/schemas" @@ -46,7 +45,6 @@ func TestParseTableName(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.SnakeMapper{}, - caches.NewManager(), ) table, err := parser.Parse(reflect.ValueOf(new(ParseTableName1))) assert.NoError(t, err) @@ -67,7 +65,6 @@ func TestParseTableComment(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.SnakeMapper{}, - caches.NewManager(), ) table, err := parser.Parse(reflect.ValueOf(new(ParseTableComment))) @@ -97,7 +94,6 @@ func TestUnexportField(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.SnakeMapper{}, - caches.NewManager(), ) type VanilaStruct struct { @@ -130,7 +126,6 @@ func TestParseWithOtherIdentifier(t *testing.T) { dialects.QueryDialect("mysql"), names.SameMapper{}, names.SnakeMapper{}, - caches.NewManager(), ) type StructWithDBTag struct { @@ -154,7 +149,6 @@ func TestParseWithIgnore(t *testing.T) { dialects.QueryDialect("mysql"), names.SameMapper{}, names.SnakeMapper{}, - caches.NewManager(), ) type StructWithIgnoreTag struct { @@ -173,7 +167,6 @@ func TestParseWithAutoincrement(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithAutoIncrement struct { @@ -195,7 +188,6 @@ func TestParseWithAutoincrement2(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithAutoIncrement2 struct { @@ -218,7 +210,6 @@ func TestParseWithNullable(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithNullable struct { @@ -243,7 +234,6 @@ func TestParseWithTimes(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithTimes struct { @@ -276,7 +266,6 @@ func TestParseWithExtends(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithEmbed struct { @@ -307,59 +296,12 @@ func TestParseWithExtends(t *testing.T) { assert.True(t, table.Columns()[3].IsDeleted) } -func TestParseWithCache(t *testing.T) { - parser := NewParser( - "db", - dialects.QueryDialect("mysql"), - names.SnakeMapper{}, - names.GonicMapper{}, - caches.NewManager(), - ) - - type StructWithCache struct { - Name string `db:"cache"` - } - - table, err := parser.Parse(reflect.ValueOf(new(StructWithCache))) - assert.NoError(t, err) - assert.EqualValues(t, "struct_with_cache", table.Name) - assert.EqualValues(t, 1, len(table.Columns())) - assert.EqualValues(t, "name", table.Columns()[0].Name) - assert.True(t, table.Columns()[0].Nullable) - cacher := parser.cacherMgr.GetCacher(table.Name) - assert.NotNil(t, cacher) -} - -func TestParseWithNoCache(t *testing.T) { - parser := NewParser( - "db", - dialects.QueryDialect("mysql"), - names.SnakeMapper{}, - names.GonicMapper{}, - caches.NewManager(), - ) - - type StructWithNoCache struct { - Name string `db:"nocache"` - } - - table, err := parser.Parse(reflect.ValueOf(new(StructWithNoCache))) - assert.NoError(t, err) - assert.EqualValues(t, "struct_with_no_cache", table.Name) - assert.EqualValues(t, 1, len(table.Columns())) - assert.EqualValues(t, "name", table.Columns()[0].Name) - assert.True(t, table.Columns()[0].Nullable) - cacher := parser.cacherMgr.GetCacher(table.Name) - assert.Nil(t, cacher) -} - func TestParseWithEnum(t *testing.T) { parser := NewParser( "db", dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithEnum struct { @@ -385,7 +327,6 @@ func TestParseWithSet(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithSet struct { @@ -411,7 +352,6 @@ func TestParseWithIndex(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithIndex struct { @@ -441,7 +381,6 @@ func TestParseWithVersion(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithVersion struct { @@ -466,7 +405,6 @@ func TestParseWithLocale(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithLocale struct { @@ -490,7 +428,6 @@ func TestParseWithDefault(t *testing.T) { dialects.QueryDialect("mysql"), names.SnakeMapper{}, names.GonicMapper{}, - caches.NewManager(), ) type StructWithDefault struct { @@ -516,7 +453,6 @@ func TestParseWithOnlyToDB(t *testing.T) { "DB": true, }, names.SnakeMapper{}, - caches.NewManager(), ) type StructWithOnlyToDB struct { @@ -542,7 +478,6 @@ func TestParseWithJSON(t *testing.T) { "JSON": true, }, names.SnakeMapper{}, - caches.NewManager(), ) type StructWithJSON struct { @@ -565,7 +500,6 @@ func TestParseWithJSONB(t *testing.T) { "JSONB": true, }, names.SnakeMapper{}, - caches.NewManager(), ) type StructWithJSONB struct { @@ -590,7 +524,6 @@ func TestParseWithSQLType(t *testing.T) { names.GonicMapper{ "UUID": true, }, - caches.NewManager(), ) type StructWithSQLType struct { diff --git a/tags/tag.go b/tags/tag.go index 05654375..cb5ac786 100644 --- a/tags/tag.go +++ b/tags/tag.go @@ -90,8 +90,6 @@ type Context struct { isUnique bool indexNames map[string]int parser *Parser - hasCacheTag bool - hasNoCacheTag bool ignoreNext bool isUnsigned bool } @@ -118,8 +116,6 @@ var defaultTagHandlers = map[string]Handler{ "NOTNULL": NotNullTagHandler, "INDEX": IndexTagHandler, "UNIQUE": UniqueTagHandler, - "CACHE": CacheTagHandler, - "NOCACHE": NoCacheTagHandler, "COMMENT": CommentTagHandler, "EXTENDS": ExtendsTagHandler, "UNSIGNED": UnsignedTagHandler, @@ -391,19 +387,3 @@ func ExtendsTagHandler(ctx *Context) error { } return ErrIgnoreField } - -// CacheTagHandler describes cache tag handler -func CacheTagHandler(ctx *Context) error { - if !ctx.hasCacheTag { - ctx.hasCacheTag = true - } - return nil -} - -// NoCacheTagHandler describes nocache tag handler -func NoCacheTagHandler(ctx *Context) error { - if !ctx.hasNoCacheTag { - ctx.hasNoCacheTag = true - } - return nil -} diff --git a/tests/cache_test.go b/tests/cache_test.go deleted file mode 100644 index 03b6fc0d..00000000 --- a/tests/cache_test.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tests - -import ( - "testing" - "time" - - "xorm.io/xorm/v2/caches" - - "github.com/stretchr/testify/assert" -) - -func TestCacheFind(t *testing.T) { - assert.NoError(t, PrepareEngine()) - - type MailBox struct { - Id int64 `xorm:"pk"` - Username string - Password string - } - - oldCacher := testEngine.GetDefaultCacher() - cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000) - testEngine.SetDefaultCacher(cacher) - - assert.NoError(t, testEngine.Sync(new(MailBox))) - - inserts := []*MailBox{ - { - Id: 0, - Username: "user1", - Password: "pass1", - }, - { - Id: 1, - Username: "user2", - Password: "pass2", - }, - } - _, err := testEngine.Insert(inserts[0], inserts[1]) - assert.NoError(t, err) - - var boxes []MailBox - assert.NoError(t, testEngine.Find(&boxes)) - assert.EqualValues(t, 2, len(boxes)) - for i, box := range boxes { - assert.Equal(t, inserts[i].Id, box.Id) - assert.Equal(t, inserts[i].Username, box.Username) - assert.Equal(t, inserts[i].Password, box.Password) - } - - boxes = make([]MailBox, 0, 2) - assert.NoError(t, testEngine.Find(&boxes)) - assert.EqualValues(t, 2, len(boxes)) - for i, box := range boxes { - assert.Equal(t, inserts[i].Id, box.Id) - assert.Equal(t, inserts[i].Username, box.Username) - assert.Equal(t, inserts[i].Password, box.Password) - } - - boxes = make([]MailBox, 0, 2) - assert.NoError(t, testEngine.Alias("a").Where("`a`.`id`> -1"). - Asc("`a`.`id`").Find(&boxes)) - assert.EqualValues(t, 2, len(boxes)) - for i, box := range boxes { - assert.Equal(t, inserts[i].Id, box.Id) - assert.Equal(t, inserts[i].Username, box.Username) - assert.Equal(t, inserts[i].Password, box.Password) - } - - type MailBox4 struct { - Id int64 - Username string - Password string - } - - boxes2 := make([]MailBox4, 0, 2) - assert.NoError(t, testEngine.Table("mail_box").Where("`mail_box`.`id` > -1"). - Asc("mail_box.id").Find(&boxes2)) - assert.EqualValues(t, 2, len(boxes2)) - for i, box := range boxes2 { - assert.Equal(t, inserts[i].Id, box.Id) - assert.Equal(t, inserts[i].Username, box.Username) - assert.Equal(t, inserts[i].Password, box.Password) - } - - testEngine.SetDefaultCacher(oldCacher) -} - -func TestCacheFind2(t *testing.T) { - assert.NoError(t, PrepareEngine()) - - type MailBox2 struct { - Id uint64 `xorm:"pk"` - Username string - Password string - } - - oldCacher := testEngine.GetDefaultCacher() - cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000) - testEngine.SetDefaultCacher(cacher) - - assert.NoError(t, testEngine.Sync(new(MailBox2))) - - inserts := []*MailBox2{ - { - Id: 0, - Username: "user1", - Password: "pass1", - }, - { - Id: 1, - Username: "user2", - Password: "pass2", - }, - } - _, err := testEngine.Insert(inserts[0], inserts[1]) - assert.NoError(t, err) - - var boxes []MailBox2 - assert.NoError(t, testEngine.Find(&boxes)) - assert.EqualValues(t, 2, len(boxes)) - for i, box := range boxes { - assert.Equal(t, inserts[i].Id, box.Id) - assert.Equal(t, inserts[i].Username, box.Username) - assert.Equal(t, inserts[i].Password, box.Password) - } - - boxes = make([]MailBox2, 0, 2) - assert.NoError(t, testEngine.Find(&boxes)) - assert.EqualValues(t, 2, len(boxes)) - for i, box := range boxes { - assert.Equal(t, inserts[i].Id, box.Id) - assert.Equal(t, inserts[i].Username, box.Username) - assert.Equal(t, inserts[i].Password, box.Password) - } - - testEngine.SetDefaultCacher(oldCacher) -} - -func TestCacheGet(t *testing.T) { - assert.NoError(t, PrepareEngine()) - - type MailBox3 struct { - Id uint64 - Username string - Password string - } - - oldCacher := testEngine.GetDefaultCacher() - cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000) - testEngine.SetDefaultCacher(cacher) - - assert.NoError(t, testEngine.Sync(new(MailBox3))) - - inserts := []*MailBox3{ - { - Username: "user1", - Password: "pass1", - }, - } - _, err := testEngine.Insert(inserts[0]) - assert.NoError(t, err) - - var box1 MailBox3 - has, err := testEngine.Where("`id` = ?", inserts[0].Id).Get(&box1) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, "user1", box1.Username) - assert.EqualValues(t, "pass1", box1.Password) - - var box2 MailBox3 - has, err = testEngine.Where("`id` = ?", inserts[0].Id).Get(&box2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, "user1", box2.Username) - assert.EqualValues(t, "pass1", box2.Password) - - testEngine.SetDefaultCacher(oldCacher) -} diff --git a/tests/session_delete_test.go b/tests/session_delete_test.go index afc9afbf..2e546873 100644 --- a/tests/session_delete_test.go +++ b/tests/session_delete_test.go @@ -9,7 +9,6 @@ import ( "testing" "time" - "xorm.io/xorm/v2/caches" "xorm.io/xorm/v2/schemas" "github.com/stretchr/testify/assert" @@ -217,38 +216,6 @@ func TestDeleted(t *testing.T) { assert.EqualValues(t, 2, len(records3)) } -func TestCacheDelete(t *testing.T) { - assert.NoError(t, PrepareEngine()) - - oldCacher := testEngine.GetDefaultCacher() - cacher := caches.NewLRUCacher(caches.NewMemoryStore(), 1000) - testEngine.SetDefaultCacher(cacher) - - type CacheDeleteStruct struct { - Id int64 - } - - err := testEngine.CreateTables(&CacheDeleteStruct{}) - assert.NoError(t, err) - - _, err = testEngine.Insert(&CacheDeleteStruct{}) - assert.NoError(t, err) - - aff, err := testEngine.Delete(&CacheDeleteStruct{ - Id: 1, - }) - assert.NoError(t, err) - assert.EqualValues(t, aff, 1) - - aff, err = testEngine.Unscoped().Delete(&CacheDeleteStruct{ - Id: 1, - }) - assert.NoError(t, err) - assert.EqualValues(t, aff, 0) - - testEngine.SetDefaultCacher(oldCacher) -} - func TestUnscopeDelete(t *testing.T) { assert.NoError(t, PrepareEngine()) diff --git a/tests/session_get_test.go b/tests/session_get_test.go index d27bde28..7c521288 100644 --- a/tests/session_get_test.go +++ b/tests/session_get_test.go @@ -509,7 +509,7 @@ func TestContextGet(t *testing.T) { context := contexts.NewMemoryContextCache() var c2 ContextGetStruct - has, err := sess.ID(1).NoCache().ContextCache(context).Get(&c2) + has, err := sess.ID(1).ContextCache(context).Get(&c2) assert.NoError(t, err) assert.True(t, has) assert.EqualValues(t, 1, c2.Id) @@ -519,7 +519,7 @@ func TestContextGet(t *testing.T) { assert.True(t, len(args) > 0) var c3 ContextGetStruct - has, err = sess.ID(1).NoCache().ContextCache(context).Get(&c3) + has, err = sess.ID(1).ContextCache(context).Get(&c3) assert.NoError(t, err) assert.True(t, has) assert.EqualValues(t, 1, c3.Id) @@ -544,14 +544,14 @@ func TestContextGet2(t *testing.T) { context := contexts.NewMemoryContextCache() var c2 ContextGetStruct2 - has, err := testEngine.ID(1).NoCache().ContextCache(context).Get(&c2) + has, err := testEngine.ID(1).ContextCache(context).Get(&c2) assert.NoError(t, err) assert.True(t, has) assert.EqualValues(t, 1, c2.Id) assert.EqualValues(t, "1", c2.Name) var c3 ContextGetStruct2 - has, err = testEngine.ID(1).NoCache().ContextCache(context).Get(&c3) + has, err = testEngine.ID(1).ContextCache(context).Get(&c3) assert.NoError(t, err) assert.True(t, has) assert.EqualValues(t, 1, c3.Id) diff --git a/tests/tags_test.go b/tests/tags_test.go index 3a2f5044..8b89976c 100644 --- a/tests/tags_test.go +++ b/tests/tags_test.go @@ -508,30 +508,6 @@ func TestExtends5(t *testing.T) { } } -func TestCacheTag(t *testing.T) { - assert.NoError(t, PrepareEngine()) - - type CacheDomain struct { - Id int64 `xorm:"pk cache"` - Name string - } - - assert.NoError(t, testEngine.CreateTables(&CacheDomain{})) - assert.True(t, testEngine.GetCacher(testEngine.TableName(&CacheDomain{})) != nil) -} - -func TestNoCacheTag(t *testing.T) { - assert.NoError(t, PrepareEngine()) - - type NoCacheDomain struct { - Id int64 `xorm:"pk nocache"` - Name string - } - - assert.NoError(t, testEngine.CreateTables(&NoCacheDomain{})) - assert.True(t, testEngine.GetCacher(testEngine.TableName(&NoCacheDomain{})) == nil) -} - type IDGonicMapper struct { ID int64 } diff --git a/tests/tests.go b/tests/tests.go index 16fa0ca4..cd1e574b 100644 --- a/tests/tests.go +++ b/tests/tests.go @@ -14,7 +14,7 @@ import ( "testing" "xorm.io/xorm/v2" - "xorm.io/xorm/v2/caches" + "xorm.io/xorm/v2/dialects" "xorm.io/xorm/v2/log" "xorm.io/xorm/v2/names" @@ -30,7 +30,6 @@ var ( showSQL = flag.Bool("show_sql", true, "show generated SQLs") ptrConnStr = flag.String("conn_str", "./test.db?cache=shared&mode=rwc", "test database connection string") mapType = flag.String("map_type", "snake", "indicate the name mapping") - cacheFlag = flag.Bool("cache", false, "if enable cache") cluster = flag.Bool("cluster", false, "if this is a cluster") splitter = flag.String("splitter", ";", "the splitter on connstr for cluster") schema = flag.String("schema", "", "specify the schema") @@ -125,10 +124,6 @@ func createEngine(dbType, connStr string) error { } testEngine.ShowSQL(*showSQL) testEngine.SetLogLevel(log.LOG_DEBUG) - if *cacheFlag { - cacher := caches.NewLRUCacher(caches.NewMemoryStore(), 100000) - testEngine.SetDefaultCacher(cacher) - } if len(*mapType) > 0 { switch *mapType {