github.com/influx6/npkg@v0.8.8/nstorage/nmap/nmap.go (about) 1 package nmap 2 3 import ( 4 "sync" 5 "sync/atomic" 6 "time" 7 8 "github.com/influx6/npkg/nerror" 9 ) 10 11 //********************************************************************** 12 // AnyMap 13 //********************************************************************** 14 15 // AnyMap defines an implementation which during initial 16 // loading stores all key and value pairs. 17 // 18 // It provides a safe, concurrently usable implementation with 19 // blazing read and write speed. 20 type AnyMap struct { 21 Capacity uint 22 lock sync.Mutex 23 cache *atomic.Value 24 } 25 26 // NewAnyMap returns a new instance of a AnyMap. 27 func NewAnyMap(cap ...uint) *AnyMap { 28 var sm AnyMap 29 if len(cap) != 0 { 30 sm.Capacity = cap[0] 31 } 32 return &sm 33 } 34 35 // Get returns giving value for key. 36 func (m *AnyMap) Get(k interface{}) (value interface{}) { 37 m.GetMany(func(values map[interface{}]interface{}) { 38 value = values[k] 39 }) 40 return 41 } 42 43 // GetMany allows retrieval of many keys from underline map. 44 // 45 // WARNING: Never modify the map, ever. 46 func (m *AnyMap) GetMany(fn func(map[interface{}]interface{})) { 47 m.init() 48 var cached = m.cache.Load().(map[interface{}]interface{}) 49 fn(cached) 50 } 51 52 // Has returns true/false giving value exits for key. 53 func (m *AnyMap) Has(k string) bool { 54 var exists bool 55 m.GetMany(func(values map[interface{}]interface{}) { 56 _, exists = values[k] 57 }) 58 return exists 59 } 60 61 // Set adds giving key into underline map. 62 func (m *AnyMap) Set(k interface{}, value interface{}) { 63 m.SetMany(func(values map[interface{}]interface{}) { 64 values[k] = value 65 }) 66 } 67 68 // SetMany adds giving key into underline map. 69 func (m *AnyMap) SetMany(fn func(map[interface{}]interface{})) { 70 m.init() 71 72 var cached = m.cache.Load().(map[interface{}]interface{}) 73 var copied = CopyInterfaceKeyMap(cached) 74 fn(copied) 75 76 m.lock.Lock() 77 m.cache.Store(copied) 78 m.lock.Unlock() 79 } 80 81 func (m *AnyMap) init() { 82 m.lock.Lock() 83 if m.cache != nil { 84 m.lock.Unlock() 85 return 86 } 87 88 defer m.lock.Unlock() 89 if m.Capacity == 0 { 90 m.Capacity = 10 91 } 92 93 var newValue atomic.Value 94 var store = make(map[interface{}]interface{}, m.Capacity) 95 newValue.Store(store) 96 m.cache = &newValue 97 } 98 99 //********************************************************************** 100 // StringAnyMap 101 //********************************************************************** 102 103 // StringAnyMap defines an implementation which during initial 104 // loading stores all key and value pairs. 105 // 106 // It provides a safe, concurrently usable implementation with 107 // blazing read and write speed. 108 type StringAnyMap struct { 109 Capacity uint 110 lock sync.Mutex 111 cache *atomic.Value 112 } 113 114 // NewStringAnyMap returns a new instance of a StringAnyMap. 115 func NewStringAnyMap(cap ...uint) *StringAnyMap { 116 var sm StringAnyMap 117 if len(cap) != 0 { 118 sm.Capacity = cap[0] 119 } 120 return &sm 121 } 122 123 // Get returns giving value for key. 124 func (m *StringAnyMap) Get(k string) (value interface{}) { 125 m.GetMany(func(values map[string]interface{}) { 126 value = values[k] 127 }) 128 return 129 } 130 131 // GetMany allows retrieval of many keys from underline map. 132 // 133 // WARNING: Never modify the map, ever. 134 func (m *StringAnyMap) GetMany(fn func(map[string]interface{})) { 135 m.init() 136 137 var cached = m.cache.Load().(map[string]interface{}) 138 fn(cached) 139 } 140 141 // Has returns true/false giving value exits for key. 142 func (m *StringAnyMap) Has(k string) bool { 143 var exists bool 144 m.GetMany(func(values map[string]interface{}) { 145 _, exists = values[k] 146 }) 147 return exists 148 } 149 150 // Set adds giving key into underline map. 151 func (m *StringAnyMap) Set(k string, value interface{}) { 152 m.SetMany(func(values map[string]interface{}) { 153 values[k] = value 154 }) 155 } 156 157 // SetMany adds giving key into underline map. 158 func (m *StringAnyMap) SetMany(fn func(map[string]interface{})) { 159 m.init() 160 161 var cached = m.cache.Load().(map[string]interface{}) 162 var copied = CopyStringKeyMap(cached) 163 fn(copied) 164 165 m.lock.Lock() 166 m.cache.Store(copied) 167 m.lock.Unlock() 168 } 169 170 func (m *StringAnyMap) init() { 171 m.lock.Lock() 172 if m.cache != nil { 173 m.lock.Unlock() 174 return 175 } 176 177 defer m.lock.Unlock() 178 if m.Capacity == 0 { 179 m.Capacity = 10 180 } 181 var store = make(map[string]interface{}, m.Capacity) 182 183 var newValue atomic.Value 184 newValue.Store(store) 185 m.cache = &newValue 186 } 187 188 //********************************************************************** 189 // StringMap 190 //********************************************************************** 191 192 // StringMap defines an implementation which during initial 193 // loading stores all key and value pairs. 194 // 195 // It provides a safe, concurrently usable implementation with 196 // blazing read and write speed. 197 type StringMap struct { 198 Capacity uint 199 lock sync.Mutex 200 cache *atomic.Value 201 } 202 203 // NewStringMap returns a new instance of a StringMap. 204 func NewStringMap(cap ...uint) *StringMap { 205 var sm StringMap 206 if len(cap) != 0 { 207 sm.Capacity = cap[0] 208 } 209 return &sm 210 } 211 212 // Has returns true/false giving value exits for key. 213 func (m *StringMap) Has(k string) bool { 214 var exists bool 215 m.GetMany(func(values map[string]string) { 216 _, exists = values[k] 217 }) 218 return exists 219 } 220 221 // Get returns giving value for key. 222 func (m *StringMap) Get(k string) (value string) { 223 m.GetMany(func(values map[string]string) { 224 value = values[k] 225 }) 226 return 227 } 228 229 // GetMany allows retrieval of many keys from underline map. 230 // 231 // WARNING: Never modify the map, ever. 232 func (m *StringMap) GetMany(fn func(map[string]string)) { 233 m.init() 234 var cached = m.cache.Load().(map[string]string) 235 fn(cached) 236 } 237 238 // Set adds giving key into underline map. 239 func (m *StringMap) Set(k string, value string) { 240 m.SetMany(func(values map[string]string) { 241 values[k] = value 242 }) 243 } 244 245 // SetMany adds giving key into underline map. 246 func (m *StringMap) SetMany(fn func(map[string]string)) { 247 m.init() 248 249 var cached = m.cache.Load().(map[string]string) 250 var copied = CopyStringMap(cached) 251 fn(copied) 252 253 m.lock.Lock() 254 m.cache.Store(copied) 255 m.lock.Unlock() 256 } 257 258 func (m *StringMap) init() { 259 m.lock.Lock() 260 if m.cache != nil { 261 m.lock.Unlock() 262 return 263 } 264 265 defer m.lock.Unlock() 266 if m.Capacity == 0 { 267 m.Capacity = 10 268 } 269 var store = make(map[string]string, m.Capacity) 270 271 var newValue atomic.Value 272 newValue.Store(store) 273 m.cache = &newValue 274 } 275 276 //********************************************************************** 277 // ByteMap 278 //********************************************************************** 279 280 // ByteMap defines an implementation which during initial 281 // loading stores all key and value pairs. 282 // 283 // It provides a safe, concurrently usable implementation with 284 // blazing read and write speed. 285 type ByteMap struct { 286 Capacity uint 287 lock sync.Mutex 288 cache *atomic.Value 289 } 290 291 // NewByteMap returns a new instance of a ByteMap. 292 func NewByteMap(cap ...uint) *ByteMap { 293 var sm ByteMap 294 if len(cap) != 0 { 295 sm.Capacity = cap[0] 296 } 297 return &sm 298 } 299 300 // Has returns true/false giving value exits for key. 301 func (m *ByteMap) Has(k string) bool { 302 var exists bool 303 m.GetMany(func(values map[string][]byte) { 304 _, exists = values[k] 305 }) 306 return exists 307 } 308 309 // Get returns giving value for key. 310 // 311 // Get makes a copy of the content of the key 312 // returning that, which causes a single allocation, 313 // use GetMany to access the content of the key directly 314 // without any copy, but ensure to copy the content as 315 // necessary to avoid corruption of value. 316 func (m *ByteMap) Get(k string) (value []byte) { 317 m.GetMany(func(values map[string][]byte) { 318 if nvalue, ok := values[k]; ok { 319 var content = make([]byte, len(nvalue)) 320 copy(content, nvalue) 321 value = content 322 } 323 }) 324 return 325 } 326 327 // GetMany allows retrieval of many keys from underline map. 328 // 329 // Get makes a copy of the content of the key 330 // returning that, which causes a single allocation, 331 // use GetMany to access the content of the key directly 332 // without any copy, but ensure to copy the content as 333 // necessary to avoid corruption of value. 334 // 335 // WARNING: Never modify the map, ever. 336 func (m *ByteMap) GetMany(fn func(map[string][]byte)) { 337 m.init() 338 var cached = m.cache.Load().(map[string][]byte) 339 fn(cached) 340 } 341 342 // Set adds giving key into underline map. 343 func (m *ByteMap) Set(k string, value []byte) { 344 m.SetMany(func(values map[string][]byte) { 345 var content = make([]byte, len(value)) 346 copy(content, value) 347 values[k] = content 348 }) 349 } 350 351 // SetMany adds giving key into underline map. 352 func (m *ByteMap) SetMany(fn func(map[string][]byte)) { 353 m.init() 354 355 var cached = m.cache.Load().(map[string][]byte) 356 var copied = CopyStringBytesMap(cached) 357 fn(copied) 358 359 m.lock.Lock() 360 m.cache.Store(copied) 361 m.lock.Unlock() 362 } 363 364 func (m *ByteMap) Count() int64 { 365 m.init() 366 var cached = m.cache.Load().(map[string][]byte) 367 return int64(len(cached)) 368 } 369 370 func (m *ByteMap) init() { 371 m.lock.Lock() 372 if m.cache != nil { 373 m.lock.Unlock() 374 return 375 } 376 377 defer m.lock.Unlock() 378 if m.Capacity == 0 { 379 m.Capacity = 10 380 } 381 var store = make(map[string][]byte, m.Capacity) 382 383 var newValue atomic.Value 384 newValue.Store(store) 385 m.cache = &newValue 386 } 387 388 //********************************************************************** 389 // ExpiringByteMap 390 //********************************************************************** 391 var zeroTime = time.Time{} 392 393 // ExpiringValue defines a type which holds a giving byte value 394 // string, it has if attached a possible expiring value, which would 395 // make it unaccessible once expired. 396 type ExpiringValue struct { 397 Value []byte 398 when time.Time 399 } 400 401 // Elapsed returns the current duration left for expiring. 402 // 403 // A positive number means there is still time and a negative 404 // number means it has expired. But zero means no expiration. 405 func (ne *ExpiringValue) Elapsed() time.Duration { 406 if ne.when.IsZero() { 407 return 0 408 } 409 var current = time.Now() 410 if current.Before(ne.when) { 411 return ne.when.Sub(current) 412 } 413 return current.Sub(ne.when) 414 } 415 416 // Expired returns true/false if giving value is expired. 417 func (ne *ExpiringValue) Expired() bool { 418 if !ne.when.IsZero() { 419 var current = time.Now() 420 if current.After(ne.when) { 421 return true 422 } 423 } 424 return false 425 } 426 427 // NewExpiringValue returns a new instance of a ExpiringValue. 428 func NewExpiringValue(value []byte, ttl time.Duration) ExpiringValue { 429 var exr ExpiringValue 430 exr.Value = value 431 if ttl > 0 { 432 exr.when = time.Now().Add(ttl) 433 } 434 return exr 435 } 436 437 // ExpiringByteMap defines an implementation which during initial 438 // loading stores all key and value pairs. 439 // 440 // It provides a safe, concurrently usable implementation with 441 // blazing read and write speed. 442 type ExpiringByteMap struct { 443 Capacity uint 444 lock sync.Mutex 445 cache *atomic.Value 446 } 447 448 // NewExpiringByteMap returns a new instance of a ExpiringByteMap. 449 func NewExpiringByteMap(cap ...uint) *ExpiringByteMap { 450 var sm ExpiringByteMap 451 if len(cap) != 0 { 452 sm.Capacity = cap[0] 453 } 454 return &sm 455 } 456 457 // Has returns true/false giving value exits for key. 458 func (m *ExpiringByteMap) Has(k string) bool { 459 var exists bool 460 m.GetMany(func(values map[string]ExpiringValue) { 461 _, exists = values[k] 462 }) 463 return exists 464 } 465 466 // Get returns giving value for key. 467 // 468 // Get makes a copy of the content of the key 469 // returning that, which causes a single allocation, 470 // use GetMany to access the content of the key directly 471 // without any copy, but ensure to copy the content as 472 // necessary to avoid corruption of value. 473 func (m *ExpiringByteMap) Get(k string) (value []byte) { 474 m.GetMany(func(values map[string]ExpiringValue) { 475 if nvalue, ok := values[k]; ok { 476 if nvalue.Expired() { 477 return 478 } 479 480 var content = make([]byte, len(nvalue.Value)) 481 copy(content, nvalue.Value) 482 value = content 483 } 484 }) 485 return 486 } 487 488 func (m *ExpiringByteMap) GetAnyKeys(keys ...string) (values [][]byte, err error) { 489 values = make([][]byte, len(keys)) 490 m.GetMany(func(data map[string]ExpiringValue) { 491 for index, k := range keys { 492 if nvalue, ok := data[k]; ok { 493 if nvalue.Expired() { 494 values[index] = nil 495 continue 496 } 497 498 var content = make([]byte, len(nvalue.Value)) 499 copy(content, nvalue.Value) 500 values[index] = content 501 continue 502 } 503 values[index] = nil 504 } 505 }) 506 return 507 } 508 509 func (m *ExpiringByteMap) GetAllKeys(keys ...string) (values [][]byte, err error) { 510 values = make([][]byte, len(keys)) 511 m.GetMany(func(data map[string]ExpiringValue) { 512 for index, k := range keys { 513 if nvalue, ok := data[k]; ok { 514 if nvalue.Expired() { 515 err = nerror.New("key %q has expired", k) 516 return 517 } 518 519 var content = make([]byte, len(nvalue.Value)) 520 copy(content, nvalue.Value) 521 values[index] = content 522 continue 523 } 524 err = nerror.New("not found") 525 break 526 } 527 }) 528 return 529 } 530 531 // TTL returns the current remaining time before giving key expires. 532 func (m *ExpiringByteMap) TTL(k string) (value time.Duration) { 533 m.GetMany(func(values map[string]ExpiringValue) { 534 if nvalue, ok := values[k]; ok { 535 value = nvalue.Elapsed() 536 } 537 }) 538 return 539 } 540 541 // GetManyErr allows retrieval of many keys from underline map. 542 // 543 // Get makes a copy of the content of the key 544 // returning that, which causes a single allocation, 545 // use GetMany to access the content of the key directly 546 // without any copy, but ensure to copy the content as 547 // necessary to avoid corruption of value. 548 // 549 // You are expected to respect the expiry values of a ExpiringValue 550 // and ignore any that as expired as a cleanup will be done later. 551 // 552 // WARNING: Never modify the map, ever. 553 func (m *ExpiringByteMap) GetManyErr(fn func(map[string]ExpiringValue) error) error { 554 m.init() 555 var cached = m.cache.Load().(map[string]ExpiringValue) 556 return fn(cached) 557 } 558 559 // GetMany allows retrieval of many keys from underline map. 560 // 561 // Get makes a copy of the content of the key 562 // returning that, which causes a single allocation, 563 // use GetMany to access the content of the key directly 564 // without any copy, but ensure to copy the content as 565 // necessary to avoid corruption of value. 566 // 567 // You are expected to respect the expiry values of a ExpiringValue 568 // and ignore any that as expired as a cleanup will be done later. 569 // 570 // WARNING: Never modify the map, ever. 571 func (m *ExpiringByteMap) GetMany(fn func(map[string]ExpiringValue)) { 572 m.init() 573 var cached = m.cache.Load().(map[string]ExpiringValue) 574 fn(cached) 575 } 576 577 // Set adds giving key into underline map. 578 // 579 // if expiration is zero then giving value expiration will not be reset but left 580 // as is. 581 // 582 // Set automatically cleans up the map of expired keys. 583 func (m *ExpiringByteMap) Set(k string, value []byte, expire time.Duration) { 584 m.SetMany(func(values map[string]ExpiringValue) { 585 if nval, ok := values[k]; ok { 586 nval.Value = value 587 if expire > 0 { 588 nval.when = time.Now().Add(expire) 589 } 590 values[k] = nval 591 return 592 } 593 values[k] = NewExpiringValue(value, expire) 594 }) 595 } 596 597 // ExtendTTL extends giving key value expiration by provided value. 598 // 599 // A expiration value of zero means to persist the giving key. 600 func (m *ExpiringByteMap) ExtendTTL(k string, expire time.Duration) { 601 m.SetMany(func(values map[string]ExpiringValue) { 602 if nval, ok := values[k]; ok { 603 if expire != 0 { 604 if nval.when.IsZero() { 605 nval.when = time.Now().Add(expire) 606 } else { 607 nval.when = nval.when.Add(expire) 608 } 609 } else { 610 nval.when = zeroTime 611 } 612 values[k] = nval 613 return 614 } 615 }) 616 } 617 618 // ResetTTL resets the expiration of giving key, persisting if duration 619 // provided is zero. 620 func (m *ExpiringByteMap) ResetTTL(k string, expire time.Duration) { 621 m.SetMany(func(values map[string]ExpiringValue) { 622 if nval, ok := values[k]; ok { 623 if expire != 0 { 624 nval.when = time.Now().Add(expire) 625 } else { 626 nval.when = zeroTime 627 } 628 values[k] = nval 629 return 630 } 631 }) 632 } 633 634 func (m *ExpiringByteMap) Count() int64 { 635 m.init() 636 var cached = m.cache.Load().(map[string]ExpiringValue) 637 return int64(len(cached)) 638 } 639 640 func (m *ExpiringByteMap) Reset() { 641 m.init() 642 643 var newCache = map[string]ExpiringValue{} 644 m.lock.Lock() 645 m.cache.Store(newCache) 646 m.lock.Unlock() 647 } 648 649 // SetMany adds giving key into underline map. 650 func (m *ExpiringByteMap) SetMany(fn func(map[string]ExpiringValue)) { 651 m.init() 652 653 var cached = m.cache.Load().(map[string]ExpiringValue) 654 var copied = CopyExpiringBytesMap(cached) 655 fn(copied) 656 657 m.lock.Lock() 658 m.cache.Store(copied) 659 m.lock.Unlock() 660 } 661 662 func (m *ExpiringByteMap) init() { 663 m.lock.Lock() 664 if m.cache != nil { 665 m.lock.Unlock() 666 return 667 } 668 669 defer m.lock.Unlock() 670 if m.Capacity == 0 { 671 m.Capacity = 10 672 } 673 var store = make(map[string]ExpiringValue, m.Capacity) 674 675 var newValue atomic.Value 676 newValue.Store(store) 677 m.cache = &newValue 678 }