field_cache.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright (c) 2015 Couchbase, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package index
  15. import (
  16. "sync"
  17. )
  18. type FieldCache struct {
  19. fieldIndexes map[string]uint16
  20. indexFields []string
  21. lastFieldIndex int
  22. mutex sync.RWMutex
  23. }
  24. func NewFieldCache() *FieldCache {
  25. return &FieldCache{
  26. fieldIndexes: make(map[string]uint16),
  27. lastFieldIndex: -1,
  28. }
  29. }
  30. func (f *FieldCache) AddExisting(field string, index uint16) {
  31. f.mutex.Lock()
  32. f.addLOCKED(field, index)
  33. f.mutex.Unlock()
  34. }
  35. func (f *FieldCache) addLOCKED(field string, index uint16) uint16 {
  36. f.fieldIndexes[field] = index
  37. if len(f.indexFields) < int(index)+1 {
  38. prevIndexFields := f.indexFields
  39. f.indexFields = make([]string, int(index)+16)
  40. copy(f.indexFields, prevIndexFields)
  41. }
  42. f.indexFields[int(index)] = field
  43. if int(index) > f.lastFieldIndex {
  44. f.lastFieldIndex = int(index)
  45. }
  46. return index
  47. }
  48. // FieldNamed returns the index of the field, and whether or not it existed
  49. // before this call. if createIfMissing is true, and new field index is assigned
  50. // but the second return value will still be false
  51. func (f *FieldCache) FieldNamed(field string, createIfMissing bool) (uint16, bool) {
  52. f.mutex.RLock()
  53. if index, ok := f.fieldIndexes[field]; ok {
  54. f.mutex.RUnlock()
  55. return index, true
  56. } else if !createIfMissing {
  57. f.mutex.RUnlock()
  58. return 0, false
  59. }
  60. // trade read lock for write lock
  61. f.mutex.RUnlock()
  62. f.mutex.Lock()
  63. // need to check again with write lock
  64. if index, ok := f.fieldIndexes[field]; ok {
  65. f.mutex.Unlock()
  66. return index, true
  67. }
  68. // assign next field id
  69. index := f.addLOCKED(field, uint16(f.lastFieldIndex+1))
  70. f.mutex.Unlock()
  71. return index, false
  72. }
  73. func (f *FieldCache) FieldIndexed(index uint16) (field string) {
  74. f.mutex.RLock()
  75. if int(index) < len(f.indexFields) {
  76. field = f.indexFields[int(index)]
  77. }
  78. f.mutex.RUnlock()
  79. return field
  80. }