|
- // Copyright (c) 2015 Couchbase, Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package index
-
- import (
- "sync"
- )
-
- type FieldCache struct {
- fieldIndexes map[string]uint16
- indexFields []string
- lastFieldIndex int
- mutex sync.RWMutex
- }
-
- func NewFieldCache() *FieldCache {
- return &FieldCache{
- fieldIndexes: make(map[string]uint16),
- lastFieldIndex: -1,
- }
- }
-
- func (f *FieldCache) AddExisting(field string, index uint16) {
- f.mutex.Lock()
- f.addLOCKED(field, index)
- f.mutex.Unlock()
- }
-
- func (f *FieldCache) addLOCKED(field string, index uint16) uint16 {
- f.fieldIndexes[field] = index
- if len(f.indexFields) < int(index)+1 {
- prevIndexFields := f.indexFields
- f.indexFields = make([]string, int(index)+16)
- copy(f.indexFields, prevIndexFields)
- }
- f.indexFields[int(index)] = field
- if int(index) > f.lastFieldIndex {
- f.lastFieldIndex = int(index)
- }
- return index
- }
-
- // FieldNamed returns the index of the field, and whether or not it existed
- // before this call. if createIfMissing is true, and new field index is assigned
- // but the second return value will still be false
- func (f *FieldCache) FieldNamed(field string, createIfMissing bool) (uint16, bool) {
- f.mutex.RLock()
- if index, ok := f.fieldIndexes[field]; ok {
- f.mutex.RUnlock()
- return index, true
- } else if !createIfMissing {
- f.mutex.RUnlock()
- return 0, false
- }
- // trade read lock for write lock
- f.mutex.RUnlock()
- f.mutex.Lock()
- // need to check again with write lock
- if index, ok := f.fieldIndexes[field]; ok {
- f.mutex.Unlock()
- return index, true
- }
- // assign next field id
- index := f.addLOCKED(field, uint16(f.lastFieldIndex+1))
- f.mutex.Unlock()
- return index, false
- }
-
- func (f *FieldCache) FieldIndexed(index uint16) (field string) {
- f.mutex.RLock()
- if int(index) < len(f.indexFields) {
- field = f.indexFields[int(index)]
- }
- f.mutex.RUnlock()
- return field
- }
|