Repository: syncthing/syncthing
File: lib/db/observed.go (Go)

Code before:
	}
	return db.Put(key, bs)
}

// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) error {
	key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
	if err != nil {
		return err
	}
	return db.Delete(key)
}

// RemovePendingFolder removes all entries matching a specific folder ID.
func (db *Lowlevel) RemovePendingFolder(id string) error {
	iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
	if err != nil {
		return err
	}
	defer iter.Release()
	var iterErr error
	for iter.Next() {
		if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
			continue
		}
		if err = db.Delete(iter.Key()); err != nil {
			iterErr = err
		}
	}
	return iterErr
}

// Consolidated information about a pending folder
type PendingFolder struct {
	OfferedBy map[protocol.DeviceID]ObservedFolder `json:"offeredBy"`
}

func (db *Lowlevel) PendingFolders() (map[string]PendingFolder, error) {
	return db.PendingFoldersForDevice(protocol.EmptyDeviceID)
}

// PendingFoldersForDevice enumerates only entries matching the given device ID, unless it
// is EmptyDeviceID.  Invalid ones are dropped from the database after a info log
// message, as a side-effect.
func (db *Lowlevel) PendingFoldersForDevice(device protocol.DeviceID) (map[string]PendingFolder, error) {
	var err error
	prefixKey := []byte{KeyTypePendingFolder}
	if device != protocol.EmptyDeviceID {
		prefixKey, err = db.keyer.GeneratePendingFolderKey(nil, device[:], nil)
		if err != nil {
			return nil, err

Review comment (bug):
This was meant to give additional context and help in debugging any upcoming issues.  For me it would be important to know whether iterator creation failed (e.g. read-only operation) or one of the deletions below (mutating operation).  This is lost if all we have is the backend's error message, whatever cryptic or useful that might be.

In a function such as this one, where multiple subsequent steps can fail individually, recording enough context seems important to me.  In contrast to functions that basically do one thing and either fail or succeed.

Keeping this log message in addition to the stuff in model would not really hurt, since the circumstances under which it fails will be much more worrying than having one more log line.

An alternative approach would be to wrap the error via `fmt.Errorf("Failed to...: %w", err)`, which seems [idiomatic](https://blog.golang.org/go1.13-errors) in Go?

Code after:
		return err
	}
	return db.Put(key, bs)
}

// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) error {
	key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
	if err != nil {
		return err
	}
	return db.Delete(key)
}

// RemovePendingFolder removes all entries matching a specific folder ID.
func (db *Lowlevel) RemovePendingFolder(id string) error {
	iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
	if err != nil {
		return fmt.Errorf("creating iterator: %w", err)
	}
	defer iter.Release()
	var iterErr error
	for iter.Next() {
		if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
			continue
		}
		if err = db.Delete(iter.Key()); err != nil {
			if iterErr != nil {
				l.Debugf("Repeat error removing pending folder: %v", err)
			} else {
				iterErr = err
			}
		}
	}
	return iterErr
}

// Consolidated information about a pending folder
type PendingFolder struct {
	OfferedBy map[protocol.DeviceID]ObservedFolder `json:"offeredBy"`
}

func (db *Lowlevel) PendingFolders() (map[string]PendingFolder, error) {
	return db.PendingFoldersForDevice(protocol.EmptyDeviceID)
}

// PendingFoldersForDevice enumerates only entries matching the given device ID, unless it
// is EmptyDeviceID.  Invalid ones are dropped from the database after a info log
// message, as a side-effect.
func (db *Lowlevel) PendingFoldersForDevice(device protocol.DeviceID) (map[string]PendingFolder, error) {
	var err error