// Pop implements Pop interface func (u *UnitedQueue) Pop(key string) (string, []byte, error) { key = strings.TrimPrefix(key, "/") key = strings.TrimSuffix(key, "/") parts := strings.Split(key, "/") if len(parts) != 2 { return "", nil, utils.NewError( utils.ErrBadKey, `pop key parts error: `+utils.ItoaQuick(len(parts)), ) } tName := parts[0] lName := parts[1] u.topicsLock.RLock() t, ok := u.topics[tName] u.topicsLock.RUnlock() if !ok { // log.Printf("topic[%s] not existed.", tName) return "", nil, utils.NewError( utils.ErrTopicNotExisted, `queue pop`, ) } id, data, err := t.pop(lName) if err != nil { return "", nil, err } return utils.Acatui(key, "/", id), data, nil }
func (t *topic) removeMsgData() error { for i := t.head; i < t.tail; i++ { key := utils.Acatui(t.name, ":", i) err := t.q.delData(key) if err != nil { log.Printf("topic[%s] del data[%s] error; %s", t.name, key, err) continue } } return nil }
func (t *topic) clean() (quit bool) { quit = false t.headLock.Lock() defer t.headLock.Unlock() // starting := t.head endTime := time.Now().Add(bgCleanTimeout) // log.Printf("topic[%s] begin to clean at %d", t.name, starting) // defer func() { // if t.head != starting { // log.Printf("topic[%s] garbage[%d - %d] are cleaned", t.name, starting, t.head-1) // } // }() ending := t.getEnd() for t.head < ending { select { case <-t.quit: quit = true // log.Printf("topic[%s] catched quit at %d", t.name, t.head) return default: // nothing todo } if time.Now().After(endTime) { // log.Printf("topic[%s] cleaning timeout, break at %d", t.name, t.head) return } key := utils.Acatui(t.name, ":", t.head) err := t.q.delData(key) if err != nil { log.Printf("topic[%s] del %s error; %s", t.name, key, err) return } t.head++ err = t.exportHead() if err != nil { log.Printf("topic[%s] export head error: %s", t.name, err) return } } return }
func (t *topic) push(data []byte) error { t.tailLock.Lock() defer t.tailLock.Unlock() key := utils.Acatui(t.name, ":", t.tail) err := t.q.setData(key, data) if err != nil { return err } // log.Printf("topic[%s] %s pushed.", t.name, string(data)) t.tail++ err = t.exportTail() if err != nil { t.tail-- return err } return nil }
// MultiPop implements MultiPop interface func (u *UnitedQueue) MultiPop(key string, n int) ([]string, [][]byte, error) { key = strings.TrimPrefix(key, "/") key = strings.TrimSuffix(key, "/") parts := strings.Split(key, "/") if len(parts) != 2 { return nil, nil, utils.NewError( utils.ErrBadKey, `mPop key parts error: `+utils.ItoaQuick(len(parts)), ) } tName := parts[0] lName := parts[1] u.topicsLock.RLock() t, ok := u.topics[tName] u.topicsLock.RUnlock() if !ok { // log.Printf("topic[%s] not existed.", tName) return nil, nil, utils.NewError( utils.ErrTopicNotExisted, `queue multiPop`, ) } ids, datas, err := t.mPop(lName, n) if err != nil { return nil, nil, err } keys := make([]string, len(ids)) for i, id := range ids { keys[i] = utils.Acatui(key, "/", id) } return keys, datas, nil }
func (t *topic) mPush(datas [][]byte) error { t.tailLock.Lock() defer t.tailLock.Unlock() oldTail := t.tail for _, data := range datas { key := utils.Acatui(t.name, ":", t.tail) err := t.q.setData(key, data) if err != nil { t.tail = oldTail return err } // log.Printf("topic[%s] %s pushed.", t.name, string(data)) t.tail++ } err := t.exportTail() if err != nil { t.tail = oldTail return err } return nil }
func (t *topic) setData(id uint64, data []byte) error { key := utils.Acatui(t.name, ":", id) return t.q.setData(key, data) }
func (t *topic) getData(id uint64) ([]byte, error) { key := utils.Acatui(t.name, ":", id) return t.q.getData(key) }