예제 #1
0
// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands.
func zpop(c redis.Conn, key string) (result string, err error) {

	defer func() {
		// Return connection to normal state on error.
		if err != nil {
			c.Do("DISCARD")
		}
	}()

	// Loop until transaction is successful.
	for {
		if _, err := c.Do("WATCH", key); err != nil {
			return "", err
		}

		members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0))
		if err != nil {
			return "", err
		}
		if len(members) != 1 {
			return "", redis.ErrNil
		}

		c.Send("MULTI")
		c.Send("ZREM", key, members[0])
		queued, err := c.Do("EXEC")
		if err != nil {
			return "", err
		}

		if queued != nil {
			result = members[0]
			break
		}
	}

	return result, nil
}
예제 #2
0
func (m *baseModel) delete(id string, conn redis.Conn) error {

	m.log.Debugf("Deleting %s %s", m.idType, id)

	existing := reflect.New(m.objType).Interface()

	existingErr := m.fetch(id, existing, false, conn)
	if existingErr != nil && existingErr != RecordNotFound {
		return fmt.Errorf("Failed fetching existing %s before delete. error:%s", m.idType, existingErr)
	}

	if existingErr == RecordNotFound {

		lastUpdated, _ := m.getLastUpdated(id, conn)
		if lastUpdated == nil {
			// Hasn't ever existed...
			return existingErr
		}
		// At this point we may have a RecordNotFound, but we may as well delete again anyway, just in case
		m.log.Infof("%s id:%s appears to be already deleted, but we'll try again anyway.", m.idType, id)
	}

	defer syncFS()

	conn.Send("MULTI")
	conn.Send("SREM", m.idType+"s", id)
	conn.Send("DEL", m.idType+":"+id)
	_, err := conn.Do("EXEC")

	if m.afterDelete != nil && existingErr == nil {
		err = m.afterDelete(existing, conn)

		if err != nil {
			return fmt.Errorf("Failed on afterDelete: %s", err)
		}
	}

	if m.sendEvent != nil {
		m.sendEvent("deleted", id)
	}

	return m.markUpdated(id, time.Now(), conn)
}