diff --git a/changelog/unreleased/owncloudsql-context-and-connections.md b/changelog/unreleased/owncloudsql-context-and-connections.md new file mode 100644 index 0000000000..79215b3f7d --- /dev/null +++ b/changelog/unreleased/owncloudsql-context-and-connections.md @@ -0,0 +1,5 @@ +Enhancement: improve owncloudsql connection management + +The owncloudsql storagedriver is now aware of the request context and will close db connections when http connections are closed or time out. We also increased the max number of open connections from 10 to 100 to prevent a corner case where all connections were used but idle connections were not freed. + +https://github.com/cs3org/reva/pull/2944 \ No newline at end of file diff --git a/pkg/auth/manager/owncloudsql/accounts/accounts.go b/pkg/auth/manager/owncloudsql/accounts/accounts.go index 3b74facda5..4be882eb2b 100644 --- a/pkg/auth/manager/owncloudsql/accounts/accounts.go +++ b/pkg/auth/manager/owncloudsql/accounts/accounts.go @@ -42,8 +42,11 @@ func NewMysql(dsn string, joinUsername, joinUUID, enableMedialSearch bool) (*Acc if err != nil { return nil, errors.Wrap(err, "error connecting to the database") } + + // FIXME make configurable sqldb.SetConnMaxLifetime(time.Minute * 3) - sqldb.SetMaxOpenConns(10) + sqldb.SetConnMaxIdleTime(time.Second * 30) + sqldb.SetMaxOpenConns(100) sqldb.SetMaxIdleConns(10) err = sqldb.Ping() diff --git a/pkg/share/manager/owncloudsql/owncloudsql.go b/pkg/share/manager/owncloudsql/owncloudsql.go index ba7af7c550..a0dd336fcf 100644 --- a/pkg/share/manager/owncloudsql/owncloudsql.go +++ b/pkg/share/manager/owncloudsql/owncloudsql.go @@ -159,7 +159,7 @@ func (m *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collabora if err != nil { return nil, err } - result, err := stmt.Exec(stmtValues...) + result, err := stmt.ExecContext(ctx, stmtValues...) if err != nil { return nil, err } @@ -226,7 +226,7 @@ func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) er if err != nil { return err } - res, err := stmt.Exec(params...) + res, err := stmt.ExecContext(ctx, params...) if err != nil { return err } @@ -268,7 +268,7 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference if err != nil { return nil, err } - if _, err = stmt.Exec(params...); err != nil { + if _, err = stmt.ExecContext(ctx, params...); err != nil { return nil, err } @@ -309,7 +309,7 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ( query = fmt.Sprintf("%s AND (%s)", query, filterQuery) } - rows, err := m.db.Query(query, params...) + rows, err := m.db.QueryContext(ctx, query, params...) if err != nil { return nil, err } @@ -377,7 +377,7 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F query = fmt.Sprintf("%s AND (%s)", query, filterQuery) } query += ";" - rows, err := m.db.Query(query, params...) + rows, err := m.db.QueryContext(ctx, query, params...) if err != nil { return nil, err } @@ -464,7 +464,7 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaborat if err != nil { return err } - res, err := stmt.Exec(params...) + res, err := stmt.ExecContext(ctx, params...) if err != nil { return err } @@ -492,7 +492,7 @@ func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId) (*collabor uid := ctxpkg.ContextMustGetUser(ctx).Username s := DBShare{ID: id.OpaqueId} query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(file_source, '') as file_source, file_target, stime, permissions, share_type FROM oc_share WHERE id=? AND (uid_owner=? or uid_initiator=?)" - if err := m.db.QueryRow(query, id.OpaqueId, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.STime, &s.Permissions, &s.ShareType); err != nil { + if err := m.db.QueryRowContext(ctx, query, id.OpaqueId, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.STime, &s.Permissions, &s.ShareType); err != nil { if err == sql.ErrNoRows { return nil, errtypes.NotFound(id.OpaqueId) } @@ -514,7 +514,7 @@ func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey) (*colla return nil, err } query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(file_source, '') as file_source, file_target, id, stime, permissions, share_type FROM oc_share WHERE uid_owner=? AND file_source=? AND share_type=? AND share_with=? AND (uid_owner=? or uid_initiator=?)" - if err = m.db.QueryRow(query, owner, key.ResourceId.StorageId, shareType, shareWith, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil { + if err = m.db.QueryRowContext(ctx, query, owner, key.ResourceId.StorageId, shareType, shareWith, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil { if err == sql.ErrNoRows { return nil, errtypes.NotFound(key.String()) } @@ -562,7 +562,7 @@ func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId) (* ` s := DBShare{} - if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State, &s.ItemStorage, &s.Parent); err != nil { + if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State, &s.ItemStorage, &s.Parent); err != nil { if err == sql.ErrNoRows { return nil, errtypes.NotFound(id.OpaqueId) } @@ -592,7 +592,7 @@ func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey) query += "AND (share_with=?)" } - if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil { + if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.FileSource, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil { if err == sql.ErrNoRows { return nil, errtypes.NotFound(key.String()) } diff --git a/pkg/share/manager/owncloudsql/owncloudsql_test.go b/pkg/share/manager/owncloudsql/owncloudsql_test.go index 173b65c93e..0e8a54053b 100644 --- a/pkg/share/manager/owncloudsql/owncloudsql_test.go +++ b/pkg/share/manager/owncloudsql/owncloudsql_test.go @@ -97,7 +97,7 @@ var _ = Describe("SQL manager", func() { if err != nil { return -1, err } - result, err := stmt.Exec(stmtValues...) + result, err := stmt.ExecContext(ctx, stmtValues...) if err != nil { return -1, err } diff --git a/pkg/storage/fs/owncloudsql/filecache/filecache.go b/pkg/storage/fs/owncloudsql/filecache/filecache.go index 14d9dac172..60266d631d 100644 --- a/pkg/storage/fs/owncloudsql/filecache/filecache.go +++ b/pkg/storage/fs/owncloudsql/filecache/filecache.go @@ -19,6 +19,7 @@ package filecache import ( + "context" "crypto/md5" "database/sql" "encoding/hex" @@ -34,6 +35,9 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog/log" + + // Provides mysql drivers + _ "github.com/go-sql-driver/mysql" ) // Cache represents a oc10-style file cache @@ -88,8 +92,11 @@ func NewMysql(dsn string) (*Cache, error) { if err != nil { return nil, errors.Wrap(err, "error connecting to the database") } + + // FIXME make configurable sqldb.SetConnMaxLifetime(time.Minute * 3) - sqldb.SetMaxOpenConns(10) + sqldb.SetConnMaxIdleTime(time.Second * 30) + sqldb.SetMaxOpenConns(100) sqldb.SetMaxIdleConns(10) err = sqldb.Ping() @@ -110,7 +117,7 @@ func New(driver string, sqldb *sql.DB) (*Cache, error) { // ListStorages returns the list of numeric ids of all storages // Optionally only home storages are considered -func (c *Cache) ListStorages(onlyHome bool) ([]*Storage, error) { +func (c *Cache) ListStorages(ctx context.Context, onlyHome bool) ([]*Storage, error) { query := "" if onlyHome { mountPointConcat := "" @@ -124,7 +131,7 @@ func (c *Cache) ListStorages(onlyHome bool) ([]*Storage, error) { } else { query = "SELECT id, numeric_id FROM oc_storages" } - rows, err := c.db.Query(query) + rows, err := c.db.QueryContext(ctx, query) if err != nil { return nil, err } @@ -143,12 +150,12 @@ func (c *Cache) ListStorages(onlyHome bool) ([]*Storage, error) { } // GetStorage returns the storage with the given numeric id -func (c *Cache) GetStorage(numeridID interface{}) (*Storage, error) { +func (c *Cache) GetStorage(ctx context.Context, numeridID interface{}) (*Storage, error) { numericID, err := toIntID(numeridID) if err != nil { return nil, err } - row := c.db.QueryRow("SELECT id, numeric_id FROM oc_storages WHERE numeric_id = ?", numericID) + row := c.db.QueryRowContext(ctx, "SELECT id, numeric_id FROM oc_storages WHERE numeric_id = ?", numericID) s := &Storage{} switch err := row.Scan(&s.ID, &s.NumericID); err { case nil: @@ -159,8 +166,8 @@ func (c *Cache) GetStorage(numeridID interface{}) (*Storage, error) { } // GetNumericStorageID returns the database id for the given storage -func (c *Cache) GetNumericStorageID(id string) (int, error) { - row := c.db.QueryRow("SELECT numeric_id FROM oc_storages WHERE id = ?", id) +func (c *Cache) GetNumericStorageID(ctx context.Context, id string) (int, error) { + row := c.db.QueryRowContext(ctx, "SELECT numeric_id FROM oc_storages WHERE id = ?", id) var nid int switch err := row.Scan(&nid); err { case nil: @@ -171,20 +178,20 @@ func (c *Cache) GetNumericStorageID(id string) (int, error) { } // CreateStorage creates a new storage and returns its numeric id -func (c *Cache) CreateStorage(id string) (int, error) { +func (c *Cache) CreateStorage(ctx context.Context, id string) (int, error) { tx, err := c.db.Begin() if err != nil { return -1, err } defer func() { _ = tx.Rollback() }() - stmt, err := tx.Prepare("INSERT INTO oc_storages(id) VALUES(?)") + stmt, err := tx.PrepareContext(ctx, "INSERT INTO oc_storages(id) VALUES(?)") if err != nil { return -1, err } defer stmt.Close() - res, err := stmt.Exec(id) + res, err := stmt.ExecContext(ctx, id) if err != nil { return -1, err } @@ -198,7 +205,7 @@ func (c *Cache) CreateStorage(id string) (int, error) { "etag": "", "mimetype": "httpd/unix-directory", } - _, err = c.doInsertOrUpdate(tx, int(insertedID), data, true) + _, err = c.doInsertOrUpdate(ctx, tx, int(insertedID), data, true) if err != nil { return -1, err } @@ -212,12 +219,12 @@ func (c *Cache) CreateStorage(id string) (int, error) { } // GetStorageOwner returns the username of the owner of the given storage -func (c *Cache) GetStorageOwner(numericID interface{}) (string, error) { +func (c *Cache) GetStorageOwner(ctx context.Context, numericID interface{}) (string, error) { numericID, err := toIntID(numericID) if err != nil { return "", err } - row := c.db.QueryRow("SELECT id FROM oc_storages WHERE numeric_id = ?", numericID) + row := c.db.QueryRowContext(ctx, "SELECT id FROM oc_storages WHERE numeric_id = ?", numericID) var id string switch err := row.Scan(&id); err { case nil: @@ -228,12 +235,12 @@ func (c *Cache) GetStorageOwner(numericID interface{}) (string, error) { } // GetStorageOwnerByFileID returns the username of the owner of the given entry -func (c *Cache) GetStorageOwnerByFileID(numericID interface{}) (string, error) { +func (c *Cache) GetStorageOwnerByFileID(ctx context.Context, numericID interface{}) (string, error) { numericID, err := toIntID(numericID) if err != nil { return "", err } - row := c.db.QueryRow("SELECT id FROM oc_storages storages, oc_filecache cache WHERE storages.numeric_id = cache.storage AND cache.fileid = ?", numericID) + row := c.db.QueryRowContext(ctx, "SELECT id FROM oc_storages storages, oc_filecache cache WHERE storages.numeric_id = cache.storage AND cache.fileid = ?", numericID) var id string switch err := row.Scan(&id); err { case nil: @@ -273,7 +280,7 @@ func (c *Cache) rowToFile(row Scannable) (*File, error) { } // Get returns the cache entry for the specified storage/path -func (c *Cache) Get(s interface{}, p string) (*File, error) { +func (c *Cache) Get(ctx context.Context, s interface{}, p string) (*File, error) { storageID, err := toIntID(s) if err != nil { return nil, err @@ -282,7 +289,7 @@ func (c *Cache) Get(s interface{}, p string) (*File, error) { phashBytes := md5.Sum([]byte(p)) phash := hex.EncodeToString(phashBytes[:]) - row := c.db.QueryRow(` + row := c.db.QueryRowContext(ctx, ` SELECT fc.fileid, fc.storage, fc.path, fc.parent, fc.permissions, fc.mimetype, fc.mimepart, mt.mimetype, fc.size, fc.mtime, fc.storage_mtime, fc.encrypted, fc.unencrypted_size, @@ -294,13 +301,13 @@ func (c *Cache) Get(s interface{}, p string) (*File, error) { } // Path returns the path for the specified entry -func (c *Cache) Path(id interface{}) (string, error) { +func (c *Cache) Path(ctx context.Context, id interface{}) (string, error) { id, err := toIntID(id) if err != nil { return "", err } - row := c.db.QueryRow("SELECT path FROM oc_filecache WHERE fileid = ?", id) + row := c.db.QueryRowContext(ctx, "SELECT path FROM oc_filecache WHERE fileid = ?", id) var path string err = row.Scan(&path) if err != nil { @@ -310,7 +317,7 @@ func (c *Cache) Path(id interface{}) (string, error) { } // List returns the list of entries below the given path -func (c *Cache) List(storage interface{}, p string) ([]*File, error) { +func (c *Cache) List(ctx context.Context, storage interface{}, p string) ([]*File, error) { storageID, err := toIntID(storage) if err != nil { return nil, err @@ -318,7 +325,7 @@ func (c *Cache) List(storage interface{}, p string) ([]*File, error) { var rows *sql.Rows phash := fmt.Sprintf("%x", md5.Sum([]byte(strings.Trim(p, "/")))) - rows, err = c.db.Query(` + rows, err = c.db.QueryContext(ctx, ` SELECT fc.fileid, fc.storage, fc.path, fc.parent, fc.permissions, fc.mimetype, fc.mimepart, mt.mimetype, fc.size, fc.mtime, fc.storage_mtime, fc.encrypted, fc.unencrypted_size, @@ -344,8 +351,8 @@ func (c *Cache) List(storage interface{}, p string) ([]*File, error) { } // Permissions returns the permissions for the specified storage/path -func (c *Cache) Permissions(storage interface{}, p string) (*provider.ResourcePermissions, error) { - entry, err := c.Get(storage, p) +func (c *Cache) Permissions(ctx context.Context, storage interface{}, p string) (*provider.ResourcePermissions, error) { + entry, err := c.Get(ctx, storage, p) if err != nil { return nil, err } @@ -359,14 +366,14 @@ func (c *Cache) Permissions(storage interface{}, p string) (*provider.ResourcePe } // InsertOrUpdate creates or updates a cache entry -func (c *Cache) InsertOrUpdate(storage interface{}, data map[string]interface{}, allowEmptyParent bool) (int, error) { +func (c *Cache) InsertOrUpdate(ctx context.Context, storage interface{}, data map[string]interface{}, allowEmptyParent bool) (int, error) { tx, err := c.db.Begin() if err != nil { return -1, err } defer func() { _ = tx.Rollback() }() - id, err := c.doInsertOrUpdate(tx, storage, data, allowEmptyParent) + id, err := c.doInsertOrUpdate(ctx, tx, storage, data, allowEmptyParent) if err != nil { return -1, err } @@ -379,7 +386,7 @@ func (c *Cache) InsertOrUpdate(storage interface{}, data map[string]interface{}, return id, err } -func (c *Cache) doInsertOrUpdate(tx *sql.Tx, storage interface{}, data map[string]interface{}, allowEmptyParent bool) (int, error) { +func (c *Cache) doInsertOrUpdate(ctx context.Context, tx *sql.Tx, storage interface{}, data map[string]interface{}, allowEmptyParent bool) (int, error) { storageID, err := toIntID(storage) if err != nil { return -1, err @@ -408,7 +415,7 @@ func (c *Cache) doInsertOrUpdate(tx *sql.Tx, storage interface{}, data map[strin if path == "" { data["parent"] = -1 } else { - parent, err := c.Get(storageID, parentPath) + parent, err := c.Get(ctx, storageID, parentPath) if err == nil { data["parent"] = parent.ID } else { @@ -454,7 +461,7 @@ func (c *Cache) doInsertOrUpdate(tx *sql.Tx, storage interface{}, data map[strin placeholders = append(placeholders, "?") } - err = c.insertMimetype(tx, data["mimetype"].(string)) + err = c.insertMimetype(ctx, tx, data["mimetype"].(string)) if err != nil { return -1, err } @@ -475,12 +482,12 @@ func (c *Cache) doInsertOrUpdate(tx *sql.Tx, storage interface{}, data map[strin } query += strings.Join(updates, ",") - stmt, err := tx.Prepare(query) + stmt, err := tx.PrepareContext(ctx, query) if err != nil { return -1, err } - res, err := stmt.Exec(values...) + res, err := stmt.ExecContext(ctx, values...) if err != nil { log.Err(err).Msg("could not store filecache item") return -1, err @@ -493,17 +500,17 @@ func (c *Cache) doInsertOrUpdate(tx *sql.Tx, storage interface{}, data map[strin } // Copy creates a copy of the specified entry at the target path -func (c *Cache) Copy(storage interface{}, sourcePath, targetPath string) (int, error) { +func (c *Cache) Copy(ctx context.Context, storage interface{}, sourcePath, targetPath string) (int, error) { storageID, err := toIntID(storage) if err != nil { return -1, err } - source, err := c.Get(storageID, sourcePath) + source, err := c.Get(ctx, storageID, sourcePath) if err != nil { return -1, errors.Wrap(err, "could not find source") } - row := c.db.QueryRow("SELECT mimetype FROM oc_mimetypes WHERE id=?", source.MimeType) + row := c.db.QueryRowContext(ctx, "SELECT mimetype FROM oc_mimetypes WHERE id=?", source.MimeType) var mimetype string err = row.Scan(&mimetype) if err != nil { @@ -522,21 +529,21 @@ func (c *Cache) Copy(storage interface{}, sourcePath, targetPath string) (int, e "encrypted": source.Encrypted, "unencrypted_size": source.UnencryptedSize, } - return c.InsertOrUpdate(storage, data, false) + return c.InsertOrUpdate(ctx, storage, data, false) } // Move moves the specified entry to the target path -func (c *Cache) Move(storage interface{}, sourcePath, targetPath string) error { +func (c *Cache) Move(ctx context.Context, storage interface{}, sourcePath, targetPath string) error { storageID, err := toIntID(storage) if err != nil { return err } - source, err := c.Get(storageID, sourcePath) + source, err := c.Get(ctx, storageID, sourcePath) if err != nil { return errors.Wrap(err, "could not find source") } newParentPath := strings.TrimRight(filepath.Dir(targetPath), "/") - newParent, err := c.Get(storageID, newParentPath) + newParent, err := c.Get(ctx, storageID, newParentPath) if err != nil { return errors.Wrap(err, "could not find new parent") } @@ -552,12 +559,12 @@ func (c *Cache) Move(storage interface{}, sourcePath, targetPath string) error { } defer stmt.Close() phashBytes := md5.Sum([]byte(targetPath)) - _, err = stmt.Exec(newParent.ID, targetPath, filepath.Base(targetPath), hex.EncodeToString(phashBytes[:]), storageID, source.ID) + _, err = stmt.ExecContext(ctx, newParent.ID, targetPath, filepath.Base(targetPath), hex.EncodeToString(phashBytes[:]), storageID, source.ID) if err != nil { return err } - childRows, err := tx.Query("SELECT fileid, path FROM oc_filecache WHERE parent = ?", source.ID) + childRows, err := tx.QueryContext(ctx, "SELECT fileid, path FROM oc_filecache WHERE parent = ?", source.ID) if err != nil { return err } @@ -578,7 +585,7 @@ func (c *Cache) Move(storage interface{}, sourcePath, targetPath string) error { for id, path := range children { path = strings.ReplaceAll(path, sourcePath, targetPath) phashBytes = md5.Sum([]byte(path)) - _, err = stmt.Exec(source.ID, path, filepath.Base(path), hex.EncodeToString(phashBytes[:]), storageID, id) + _, err = stmt.ExecContext(ctx, source.ID, path, filepath.Base(path), hex.EncodeToString(phashBytes[:]), storageID, id) if err != nil { return err } @@ -588,20 +595,20 @@ func (c *Cache) Move(storage interface{}, sourcePath, targetPath string) error { } // Purge removes the specified storage/path from the cache without putting it into the trash -func (c *Cache) Purge(storage interface{}, path string) error { +func (c *Cache) Purge(ctx context.Context, storage interface{}, path string) error { storageID, err := toIntID(storage) if err != nil { return err } phashBytes := md5.Sum([]byte(path)) phash := hex.EncodeToString(phashBytes[:]) - _, err = c.db.Exec("DELETE FROM oc_filecache WHERE storage = ? and path_hash = ?", storageID, phash) + _, err = c.db.ExecContext(ctx, "DELETE FROM oc_filecache WHERE storage = ? and path_hash = ?", storageID, phash) return err } // Delete removes the specified storage/path from the cache -func (c *Cache) Delete(storage interface{}, user, path, trashPath string) error { - err := c.Move(storage, path, trashPath) +func (c *Cache) Delete(ctx context.Context, storage interface{}, user, path, trashPath string) error { + err := c.Move(ctx, storage, path, trashPath) if err != nil { return err } @@ -610,7 +617,7 @@ func (c *Cache) Delete(storage interface{}, user, path, trashPath string) error parts := re.FindStringSubmatch(filepath.Base(trashPath)) query := "INSERT INTO oc_files_trash(user,id,timestamp,location) VALUES(?,?,?,?)" - stmt, err := c.db.Prepare(query) + stmt, err := c.db.PrepareContext(ctx, query) if err != nil { return err } @@ -619,7 +626,7 @@ func (c *Cache) Delete(storage interface{}, user, path, trashPath string) error if err != nil { return err } - _, err = stmt.Exec(user, filepath.Base(parts[1]), parts[2], relativeLocation) + _, err = stmt.ExecContext(ctx, user, filepath.Base(parts[1]), parts[2], relativeLocation) if err != nil { log.Err(err).Msg("could not store filecache item") return err @@ -629,8 +636,8 @@ func (c *Cache) Delete(storage interface{}, user, path, trashPath string) error } // GetRecycleItem returns the specified recycle item -func (c *Cache) GetRecycleItem(user, path string, timestamp int) (*TrashItem, error) { - row := c.db.QueryRow("SELECT auto_id, id, location FROM oc_files_trash WHERE id = ? AND user = ? AND timestamp = ?", path, user, timestamp) +func (c *Cache) GetRecycleItem(ctx context.Context, user, path string, timestamp int) (*TrashItem, error) { + row := c.db.QueryRowContext(ctx, "SELECT auto_id, id, location FROM oc_files_trash WHERE id = ? AND user = ? AND timestamp = ?", path, user, timestamp) var autoID int var id, location string err := row.Scan(&autoID, &id, &location) @@ -648,30 +655,30 @@ func (c *Cache) GetRecycleItem(user, path string, timestamp int) (*TrashItem, er } // EmptyRecycle clears the recycle bin for the given user -func (c *Cache) EmptyRecycle(user string) error { - _, err := c.db.Exec("DELETE FROM oc_files_trash WHERE user = ?", user) +func (c *Cache) EmptyRecycle(ctx context.Context, user string) error { + _, err := c.db.ExecContext(ctx, "DELETE FROM oc_files_trash WHERE user = ?", user) if err != nil { return err } - storage, err := c.GetNumericStorageID("home::" + user) + storage, err := c.GetNumericStorageID(ctx, "home::"+user) if err != nil { return err } - _, err = c.db.Exec("DELETE FROM oc_filecache WHERE storage = ? AND PATH LIKE ?", storage, "files_trashbin/%") + _, err = c.db.ExecContext(ctx, "DELETE FROM oc_filecache WHERE storage = ? AND PATH LIKE ?", storage, "files_trashbin/%") return err } // DeleteRecycleItem deletes the specified item from the trash -func (c *Cache) DeleteRecycleItem(user, path string, timestamp int) error { - _, err := c.db.Exec("DELETE FROM oc_files_trash WHERE id = ? AND user = ? AND timestamp = ?", path, user, timestamp) +func (c *Cache) DeleteRecycleItem(ctx context.Context, user, path string, timestamp int) error { + _, err := c.db.ExecContext(ctx, "DELETE FROM oc_files_trash WHERE id = ? AND user = ? AND timestamp = ?", path, user, timestamp) return err } // PurgeRecycleItem deletes the specified item from the filecache and the trash -func (c *Cache) PurgeRecycleItem(user, path string, timestamp int, isVersionFile bool) error { - row := c.db.QueryRow("SELECT auto_id, location FROM oc_files_trash WHERE id = ? AND user = ? AND timestamp = ?", path, user, timestamp) +func (c *Cache) PurgeRecycleItem(ctx context.Context, user, path string, timestamp int, isVersionFile bool) error { + row := c.db.QueryRowContext(ctx, "SELECT auto_id, location FROM oc_files_trash WHERE id = ? AND user = ? AND timestamp = ?", path, user, timestamp) var autoID int var location string err := row.Scan(&autoID, &location) @@ -679,12 +686,12 @@ func (c *Cache) PurgeRecycleItem(user, path string, timestamp int, isVersionFile return err } - _, err = c.db.Exec("DELETE FROM oc_files_trash WHERE auto_id=?", autoID) + _, err = c.db.ExecContext(ctx, "DELETE FROM oc_files_trash WHERE auto_id=?", autoID) if err != nil { return err } - storage, err := c.GetNumericStorageID("home::" + user) + storage, err := c.GetNumericStorageID(ctx, "home::"+user) if err != nil { return err } @@ -692,40 +699,40 @@ func (c *Cache) PurgeRecycleItem(user, path string, timestamp int, isVersionFile if isVersionFile { trashType = "versions" } - item, err := c.Get(storage, filepath.Join("files_trashbin", trashType, path+".d"+strconv.Itoa(timestamp))) + item, err := c.Get(ctx, storage, filepath.Join("files_trashbin", trashType, path+".d"+strconv.Itoa(timestamp))) if err != nil { return err } - _, err = c.db.Exec("DELETE FROM oc_filecache WHERE fileid=? OR parent=?", item.ID, item.ID) + _, err = c.db.ExecContext(ctx, "DELETE FROM oc_filecache WHERE fileid=? OR parent=?", item.ID, item.ID) return err } // SetEtag set a new etag for the specified item -func (c *Cache) SetEtag(storage interface{}, path, etag string) error { +func (c *Cache) SetEtag(ctx context.Context, storage interface{}, path, etag string) error { storageID, err := toIntID(storage) if err != nil { return err } - source, err := c.Get(storageID, path) + source, err := c.Get(ctx, storageID, path) if err != nil { return errors.Wrap(err, "could not find source") } - stmt, err := c.db.Prepare("UPDATE oc_filecache SET etag=? WHERE storage = ? AND fileid=?") + stmt, err := c.db.PrepareContext(ctx, "UPDATE oc_filecache SET etag=? WHERE storage = ? AND fileid=?") if err != nil { return err } - _, err = stmt.Exec(etag, storageID, source.ID) + _, err = stmt.ExecContext(ctx, etag, storageID, source.ID) return err } -func (c *Cache) insertMimetype(tx *sql.Tx, mimetype string) error { +func (c *Cache) insertMimetype(ctx context.Context, tx *sql.Tx, mimetype string) error { insertPart := func(v string) error { - stmt, err := tx.Prepare("INSERT INTO oc_mimetypes(mimetype) VALUES(?)") + stmt, err := tx.PrepareContext(ctx, "INSERT INTO oc_mimetypes(mimetype) VALUES(?)") if err != nil { return err } - _, err = stmt.Exec(v) + _, err = stmt.ExecContext(ctx, v) if err != nil { if strings.Contains(err.Error(), "UNIQUE") || strings.Contains(err.Error(), "Error 1062") { return nil // Already exists diff --git a/pkg/storage/fs/owncloudsql/filecache/filecache_test.go b/pkg/storage/fs/owncloudsql/filecache/filecache_test.go index df0eaee230..e4cb05743f 100644 --- a/pkg/storage/fs/owncloudsql/filecache/filecache_test.go +++ b/pkg/storage/fs/owncloudsql/filecache/filecache_test.go @@ -19,6 +19,7 @@ package filecache_test import ( + "context" "database/sql" "io/ioutil" "os" @@ -37,9 +38,12 @@ var _ = Describe("Filecache", func() { cache *filecache.Cache testDbFile *os.File sqldb *sql.DB + ctx context.Context ) BeforeEach(func() { + ctx = context.Background() + var err error testDbFile, err = ioutil.TempFile("", "example") Expect(err).ToNot(HaveOccurred()) @@ -65,7 +69,7 @@ var _ = Describe("Filecache", func() { Describe("ListStorages", func() { It("returns all storages", func() { - storages, err := cache.ListStorages(false) + storages, err := cache.ListStorages(ctx, false) Expect(err).ToNot(HaveOccurred()) Expect(len(storages)).To(Equal(2)) ids := []string{} @@ -79,7 +83,7 @@ var _ = Describe("Filecache", func() { }) It("returns all home storages", func() { - storages, err := cache.ListStorages(true) + storages, err := cache.ListStorages(ctx, true) Expect(err).ToNot(HaveOccurred()) Expect(len(storages)).To(Equal(1)) Expect(storages[0].ID).To(Equal("home::admin")) @@ -89,26 +93,26 @@ var _ = Describe("Filecache", func() { Describe("GetStorage", func() { It("returns an error when the id is invalid", func() { - s, err := cache.GetStorage("foo") + s, err := cache.GetStorage(ctx, "foo") Expect(err).To(HaveOccurred()) Expect(s).To(BeNil()) }) It("returns an error when the id doesn't exist", func() { - s, err := cache.GetStorage(100) + s, err := cache.GetStorage(ctx, 100) Expect(err).To(HaveOccurred()) Expect(s).To(BeNil()) }) It("returns the storage", func() { - s, err := cache.GetStorage(1) + s, err := cache.GetStorage(ctx, 1) Expect(err).ToNot(HaveOccurred()) Expect(s.ID).To(Equal("home::admin")) Expect(s.NumericID).To(Equal(1)) }) It("takes string ids", func() { - s, err := cache.GetStorage("1") + s, err := cache.GetStorage(ctx, "1") Expect(err).ToNot(HaveOccurred()) Expect(s.ID).To(Equal("home::admin")) Expect(s.NumericID).To(Equal(1)) @@ -117,7 +121,7 @@ var _ = Describe("Filecache", func() { Describe("GetNumericStorageID", func() { It("returns the proper storage id", func() { - nid, err := cache.GetNumericStorageID("home::admin") + nid, err := cache.GetNumericStorageID(ctx, "home::admin") Expect(err).ToNot(HaveOccurred()) Expect(nid).To(Equal(1)) }) @@ -125,7 +129,7 @@ var _ = Describe("Filecache", func() { Describe("GetStorageOwner", func() { It("returns the owner", func() { - owner, err := cache.GetStorageOwner("1") + owner, err := cache.GetStorageOwner(ctx, "1") Expect(err).ToNot(HaveOccurred()) Expect(owner).To(Equal("admin")) }) @@ -133,22 +137,22 @@ var _ = Describe("Filecache", func() { Describe("CreateStorage", func() { It("creates the storage and a root item", func() { - id, err := cache.CreateStorage("bar") + id, err := cache.CreateStorage(ctx, "bar") Expect(err).ToNot(HaveOccurred()) Expect(id > 0).To(BeTrue()) - owner, err := cache.GetStorageOwner(id) + owner, err := cache.GetStorageOwner(ctx, id) Expect(err).ToNot(HaveOccurred()) Expect(owner).To(Equal("bar")) - file, err := cache.Get(1, "") + file, err := cache.Get(ctx, 1, "") Expect(err).ToNot(HaveOccurred()) Expect(file).ToNot(BeNil()) }) }) Describe("GetStorageOwnerByFileID", func() { It("returns the owner", func() { - owner, err := cache.GetStorageOwnerByFileID("10") + owner, err := cache.GetStorageOwnerByFileID(ctx, "10") Expect(err).ToNot(HaveOccurred()) Expect(owner).To(Equal("admin")) }) @@ -157,7 +161,7 @@ var _ = Describe("Filecache", func() { Describe("Get", func() { It("gets existing files", func() { path := "files/Photos/Portugal.jpg" - file, err := cache.Get(1, path) + file, err := cache.Get(ctx, 1, path) Expect(err).ToNot(HaveOccurred()) Expect(file).ToNot(BeNil()) Expect(file.ID).To(Equal(10)) @@ -180,19 +184,19 @@ var _ = Describe("Filecache", func() { Describe("List", func() { It("lists all entries", func() { - list, err := cache.List(1, "") + list, err := cache.List(ctx, 1, "") Expect(err).ToNot(HaveOccurred()) Expect(len(list)).To(Equal(3)) }) It("filters", func() { - list, err := cache.List(1, "files_trashbin/") + list, err := cache.List(ctx, 1, "files_trashbin/") Expect(err).ToNot(HaveOccurred()) Expect(len(list)).To(Equal(3)) }) It("filters deep", func() { - list, err := cache.List(1, "files/Photos/") + list, err := cache.List(ctx, 1, "files/Photos/") Expect(err).ToNot(HaveOccurred()) Expect(len(list)).To(Equal(3)) }) @@ -200,13 +204,13 @@ var _ = Describe("Filecache", func() { Describe("Path", func() { It("returns the path", func() { - path, err := cache.Path(10) + path, err := cache.Path(ctx, 10) Expect(err).ToNot(HaveOccurred()) Expect(path).To(Equal("files/Photos/Portugal.jpg")) }) It("returns the path when given a string id", func() { - path, err := cache.Path("10") + path, err := cache.Path(ctx, "10") Expect(err).ToNot(HaveOccurred()) Expect(path).To(Equal("files/Photos/Portugal.jpg")) }) @@ -219,21 +223,21 @@ var _ = Describe("Filecache", func() { "mimetype": "httpd/unix-directory", "etag": "abcdefg", } - _, err := cache.InsertOrUpdate(3, data, false) + _, err := cache.InsertOrUpdate(ctx, 3, data, false) Expect(err).To(MatchError("missing required data")) data = map[string]interface{}{ "path": "files/Photos/foo.jpg", "etag": "abcdefg", } - _, err = cache.InsertOrUpdate(3, data, false) + _, err = cache.InsertOrUpdate(ctx, 3, data, false) Expect(err).To(MatchError("missing required data")) data = map[string]interface{}{ "path": "files/Photos/foo.jpg", "mimetype": "httpd/unix-directory", } - _, err = cache.InsertOrUpdate(3, data, false) + _, err = cache.InsertOrUpdate(ctx, 3, data, false) Expect(err).To(MatchError("missing required data")) }) @@ -243,11 +247,11 @@ var _ = Describe("Filecache", func() { "mimetype": "httpd/unix-directory", "etag": "abcdefg", } - id, err := cache.InsertOrUpdate(1, data, false) + id, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) Expect(id).To(Equal(18)) - entry, err := cache.Get(1, "files/Photos/foo.jpg") + entry, err := cache.Get(ctx, 1, "files/Photos/foo.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.Path).To(Equal("files/Photos/foo.jpg")) Expect(entry.Name).To(Equal("foo.jpg")) @@ -268,10 +272,10 @@ var _ = Describe("Filecache", func() { "encrypted": true, "unencrypted_size": 2000, } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) - entry, err := cache.Get(1, "files/Photos/foo.jpg") + entry, err := cache.Get(ctx, 1, "files/Photos/foo.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.Path).To(Equal("files/Photos/foo.jpg")) Expect(entry.Name).To(Equal("foo.jpg")) @@ -293,10 +297,10 @@ var _ = Describe("Filecache", func() { "etag": "abcdefg", } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) - entry, err := cache.Get(1, "files/Photos/foo.jpg") + entry, err := cache.Get(ctx, 1, "files/Photos/foo.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.Parent).To(Equal(9)) }) @@ -309,10 +313,10 @@ var _ = Describe("Filecache", func() { "storage_mtime": 1617702483, } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) - entry, err := cache.Get(1, "files/Photos/foo.jpg") + entry, err := cache.Get(ctx, 1, "files/Photos/foo.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.MTime).To(Equal(1617702483)) }) @@ -325,10 +329,10 @@ var _ = Describe("Filecache", func() { "mimetype": "image/jpeg", } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) - entry, err := cache.Get(1, "files/Photos/foo.jpg") + entry, err := cache.Get(ctx, 1, "files/Photos/foo.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.MimeType).To(Equal(6)) Expect(entry.MimePart).To(Equal(5)) @@ -342,10 +346,10 @@ var _ = Describe("Filecache", func() { "mimetype": "image/tiff", } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) - entry, err := cache.Get(1, "files/Photos/foo.tiff") + entry, err := cache.Get(ctx, 1, "files/Photos/foo.tiff") Expect(err).ToNot(HaveOccurred()) Expect(entry.MimeType).To(Equal(9)) Expect(entry.MimePart).To(Equal(5)) @@ -359,10 +363,10 @@ var _ = Describe("Filecache", func() { "mimetype": "image/tiff", } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) - file, err := cache.Get(1, "") + file, err := cache.Get(ctx, 1, "") Expect(err).ToNot(HaveOccurred()) Expect(file).ToNot(BeNil()) Expect(file.Name).To(Equal("")) @@ -380,20 +384,20 @@ var _ = Describe("Filecache", func() { "mimetype": "httpd/unix-directory", "etag": "abcdefg", } - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) }) It("updates the record", func() { - recordBefore, err := cache.Get(1, data["path"].(string)) + recordBefore, err := cache.Get(ctx, 1, data["path"].(string)) Expect(err).ToNot(HaveOccurred()) data["etag"] = "12345" - id, err := cache.InsertOrUpdate(1, data, false) + id, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) Expect(id).To(Equal(recordBefore.ID)) - recordAfter, err := cache.Get(1, data["path"].(string)) + recordAfter, err := cache.Get(ctx, 1, data["path"].(string)) Expect(err).ToNot(HaveOccurred()) Expect(recordBefore.Etag).To(Equal("abcdefg")) @@ -405,40 +409,40 @@ var _ = Describe("Filecache", func() { Describe("Move", func() { It("moves a file", func() { - err := cache.Move(1, "files/Photos/Portugal.jpg", "files/Documents/Portugal.jpg") + err := cache.Move(ctx, 1, "files/Photos/Portugal.jpg", "files/Documents/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, "files/Photos/Portugal.jpg") + _, err = cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).To(HaveOccurred()) - newEntry, err := cache.Get(1, "files/Documents/Portugal.jpg") + newEntry, err := cache.Get(ctx, 1, "files/Documents/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) Expect(newEntry.Path).To(Equal("files/Documents/Portugal.jpg")) }) It("moves a file while changing its name", func() { - err := cache.Move(1, "files/Photos/Portugal.jpg", "files/Documents/Spain.jpg") + err := cache.Move(ctx, 1, "files/Photos/Portugal.jpg", "files/Documents/Spain.jpg") Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, "files/Photos/Portugal.jpg") + _, err = cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).To(HaveOccurred()) - newEntry, err := cache.Get(1, "files/Documents/Spain.jpg") + newEntry, err := cache.Get(ctx, 1, "files/Documents/Spain.jpg") Expect(err).ToNot(HaveOccurred()) Expect(newEntry.Path).To(Equal("files/Documents/Spain.jpg")) Expect(newEntry.Name).To(Equal("Spain.jpg")) }) It("moves a directory", func() { - err := cache.Move(1, "files/Photos", "files/Foo") + err := cache.Move(ctx, 1, "files/Photos", "files/Foo") Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, "files/Photos") + _, err = cache.Get(ctx, 1, "files/Photos") Expect(err).To(HaveOccurred()) - _, err = cache.Get(1, "files/Photos/Portugal.jpg") + _, err = cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).To(HaveOccurred()) - newEntry, err := cache.Get(1, "files/Foo/Portugal.jpg") + newEntry, err := cache.Get(ctx, 1, "files/Foo/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) Expect(newEntry.Path).To(Equal("files/Foo/Portugal.jpg")) }) @@ -446,14 +450,14 @@ var _ = Describe("Filecache", func() { Describe("SetEtag", func() { It("updates the etag", func() { - entry, err := cache.Get(1, "files/Photos/Portugal.jpg") + entry, err := cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.Etag).To(Equal("13cf411aefccd7183d3b117ccd0ac5f8")) - err = cache.SetEtag(1, "files/Photos/Portugal.jpg", "foo") + err = cache.SetEtag(ctx, 1, "files/Photos/Portugal.jpg", "foo") Expect(err).ToNot(HaveOccurred()) - entry, err = cache.Get(1, "files/Photos/Portugal.jpg") + entry, err = cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) Expect(entry.Etag).To(Equal("foo")) }) @@ -474,113 +478,113 @@ var _ = Describe("Filecache", func() { ) BeforeEach(func() { - _, err := cache.InsertOrUpdate(1, data, false) + _, err := cache.InsertOrUpdate(ctx, 1, data, false) Expect(err).ToNot(HaveOccurred()) }) Describe("Delete", func() { It("deletes an item", func() { - err := cache.Delete(1, "admin", filePath, trashPath) + err := cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, "files/Photos/Portugal.jpg") + _, err = cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).To(HaveOccurred()) - _, err = cache.Get(1, "files_trashbin/files/Portugal.jpg.d1619007109") + _, err = cache.Get(ctx, 1, "files_trashbin/files/Portugal.jpg.d1619007109") Expect(err).ToNot(HaveOccurred()) }) It("creates an entry in the trash table", func() { - _, err := cache.GetRecycleItem("admin", trashPathBase, trashPathTimestamp) + _, err := cache.GetRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).To(HaveOccurred()) - err = cache.Delete(1, "admin", filePath, trashPath) + err = cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - item, err := cache.GetRecycleItem("admin", trashPathBase, trashPathTimestamp) + item, err := cache.GetRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).ToNot(HaveOccurred()) Expect(item.Path).To(Equal("Photos")) }) It("rewrites the path of the children", func() { - err := cache.Delete(1, "admin", "files/Photos", "files_trashbin/files/Photos.d1619007109") + err := cache.Delete(ctx, 1, "admin", "files/Photos", "files_trashbin/files/Photos.d1619007109") Expect(err).ToNot(HaveOccurred()) }) }) Describe("EmptyRecycle", func() { It("clears the recycle bin", func() { - err := cache.Delete(1, "admin", filePath, trashPath) + err := cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - err = cache.EmptyRecycle("admin") + err = cache.EmptyRecycle(ctx, "admin") Expect(err).ToNot(HaveOccurred()) - _, err = cache.GetRecycleItem("admin", trashPathBase, trashPathTimestamp) + _, err = cache.GetRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).To(HaveOccurred()) }) }) Describe("DeleteRecycleItem", func() { It("removes the item from the trash", func() { - err := cache.Delete(1, "admin", filePath, trashPath) + err := cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - err = cache.DeleteRecycleItem("admin", trashPathBase, trashPathTimestamp) + err = cache.DeleteRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).ToNot(HaveOccurred()) - _, err = cache.GetRecycleItem("admin", trashPathBase, trashPathTimestamp) + _, err = cache.GetRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).To(HaveOccurred()) }) It("does not remove the item from the file cache", func() { - err := cache.Delete(1, "admin", filePath, trashPath) + err := cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - err = cache.DeleteRecycleItem("admin", trashPathBase, trashPathTimestamp) + err = cache.DeleteRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, trashPath) + _, err = cache.Get(ctx, 1, trashPath) Expect(err).ToNot(HaveOccurred()) }) }) Describe("PurgeRecycleItem", func() { It("removes the item from the database", func() { - err := cache.Delete(1, "admin", filePath, trashPath) + err := cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - _, err = cache.GetRecycleItem("admin", trashPathBase, trashPathTimestamp) + _, err = cache.GetRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).ToNot(HaveOccurred()) - err = cache.PurgeRecycleItem("admin", trashPathBase, trashPathTimestamp, false) + err = cache.PurgeRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp, false) Expect(err).ToNot(HaveOccurred()) - _, err = cache.GetRecycleItem("admin", trashPathBase, trashPathTimestamp) + _, err = cache.GetRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp) Expect(err).To(HaveOccurred()) }) It("removes the item from the filecache table", func() { - err := cache.Delete(1, "admin", filePath, trashPath) + err := cache.Delete(ctx, 1, "admin", filePath, trashPath) Expect(err).ToNot(HaveOccurred()) - err = cache.PurgeRecycleItem("admin", trashPathBase, trashPathTimestamp, false) + err = cache.PurgeRecycleItem(ctx, "admin", trashPathBase, trashPathTimestamp, false) Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, trashPath) + _, err = cache.Get(ctx, 1, trashPath) Expect(err).To(HaveOccurred()) }) It("removes children from the filecache table", func() { - err := cache.Delete(1, "admin", "files/Photos", "files_trashbin/files/Photos.d1619007109") + err := cache.Delete(ctx, 1, "admin", "files/Photos", "files_trashbin/files/Photos.d1619007109") Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, "files_trashbin/files/Photos.d1619007109/Portugal.jpg") + _, err = cache.Get(ctx, 1, "files_trashbin/files/Photos.d1619007109/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) - err = cache.PurgeRecycleItem("admin", "Photos", 1619007109, false) + err = cache.PurgeRecycleItem(ctx, "admin", "Photos", 1619007109, false) Expect(err).ToNot(HaveOccurred()) - _, err = cache.Get(1, "files_trashbin/files/Photos.d1619007109/Portugal.jpg") + _, err = cache.Get(ctx, 1, "files_trashbin/files/Photos.d1619007109/Portugal.jpg") Expect(err).To(HaveOccurred()) }) }) @@ -594,16 +598,16 @@ var _ = Describe("Filecache", func() { "mimetype": "httpd/unix-directory", "etag": "abcdefg", } - _, err := cache.InsertOrUpdate(1, parentData, false) + _, err := cache.InsertOrUpdate(ctx, 1, parentData, false) Expect(err).ToNot(HaveOccurred()) } - existingEntry, err := cache.Get(1, "files/Photos/Portugal.jpg") + existingEntry, err := cache.Get(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) - _, err = cache.Copy(1, "files/Photos/Portugal.jpg", "files_versions/Photos/Portugal.jpg.v1619528083") + _, err = cache.Copy(ctx, 1, "files/Photos/Portugal.jpg", "files_versions/Photos/Portugal.jpg.v1619528083") Expect(err).ToNot(HaveOccurred()) - newEntry, err := cache.Get(1, "files_versions/Photos/Portugal.jpg.v1619528083") + newEntry, err := cache.Get(ctx, 1, "files_versions/Photos/Portugal.jpg.v1619528083") Expect(err).ToNot(HaveOccurred()) Expect(newEntry.ID).ToNot(Equal(existingEntry.ID)) Expect(newEntry.MimeType).To(Equal(existingEntry.MimeType)) @@ -612,12 +616,12 @@ var _ = Describe("Filecache", func() { Describe("Permissions", func() { It("returns the permissions", func() { - perms, err := cache.Permissions(1, "files/Photos/Portugal.jpg") + perms, err := cache.Permissions(ctx, 1, "files/Photos/Portugal.jpg") Expect(err).ToNot(HaveOccurred()) Expect(perms).ToNot(BeNil()) Expect(perms.InitiateFileUpload).To(BeTrue()) - perms, err = cache.Permissions(1, "files/Photos/Teotihuacan.jpg") + perms, err = cache.Permissions(ctx, 1, "files/Photos/Teotihuacan.jpg") Expect(err).ToNot(HaveOccurred()) Expect(perms).ToNot(BeNil()) Expect(perms.InitiateFileUpload).To(BeFalse()) diff --git a/pkg/storage/fs/owncloudsql/owncloudsql.go b/pkg/storage/fs/owncloudsql/owncloudsql.go index f64978ccb9..b5b4afc5c6 100644 --- a/pkg/storage/fs/owncloudsql/owncloudsql.go +++ b/pkg/storage/fs/owncloudsql/owncloudsql.go @@ -501,14 +501,14 @@ func (fs *owncloudsqlfs) permissionSet(ctx context.Context, owner *userpb.UserId } } -func (fs *owncloudsqlfs) getStorage(ip string) (int, error) { - return fs.filecache.GetNumericStorageID("home::" + fs.getOwner(ip)) +func (fs *owncloudsqlfs) getStorage(ctx context.Context, ip string) (int, error) { + return fs.filecache.GetNumericStorageID(ctx, "home::"+fs.getOwner(ip)) } -func (fs *owncloudsqlfs) getUserStorage(user string) (int, error) { - id, err := fs.filecache.GetNumericStorageID("home::" + user) +func (fs *owncloudsqlfs) getUserStorage(ctx context.Context, user string) (int, error) { + id, err := fs.filecache.GetNumericStorageID(ctx, "home::"+user) if err != nil { - id, err = fs.filecache.CreateStorage("home::" + user) + id, err = fs.filecache.CreateStorage(ctx, "home::"+user) } return id, err } @@ -587,13 +587,13 @@ func (fs *owncloudsqlfs) GetPathByID(ctx context.Context, id *provider.ResourceI func (fs *owncloudsqlfs) resolve(ctx context.Context, ref *provider.Reference) (string, error) { if ref.GetResourceId() != nil { - p, err := fs.filecache.Path(ref.GetResourceId().OpaqueId) + p, err := fs.filecache.Path(ctx, ref.GetResourceId().OpaqueId) if err != nil { return "", err } p = strings.TrimPrefix(p, "files/") if !fs.c.EnableHome { - owner, err := fs.filecache.GetStorageOwnerByFileID(ref.GetResourceId().OpaqueId) + owner, err := fs.filecache.GetStorageOwnerByFileID(ctx, ref.GetResourceId().OpaqueId) if err != nil { return "", err } @@ -635,11 +635,11 @@ func (fs *owncloudsqlfs) readPermissions(ctx context.Context, ip string) (p *pro } // otherwise this is a share - ownerStorageID, err := fs.filecache.GetNumericStorageID("home::" + owner) + ownerStorageID, err := fs.filecache.GetNumericStorageID(ctx, "home::"+owner) if err != nil { return nil, err } - entry, err := fs.filecache.Get(ownerStorageID, fs.toDatabasePath(ip)) + entry, err := fs.filecache.Get(ctx, ownerStorageID, fs.toDatabasePath(ip)) if err != nil { return nil, err } @@ -692,7 +692,7 @@ func (fs *owncloudsqlfs) createHomeForUser(ctx context.Context, user string) err filepath.Join(fs.c.DataDirectory, user, "uploads"), } - storageID, err := fs.getUserStorage(user) + storageID, err := fs.getUserStorage(ctx, user) if err != nil { return err } @@ -713,7 +713,7 @@ func (fs *owncloudsqlfs) createHomeForUser(ctx context.Context, user string) err } allowEmptyParent := v == filepath.Join(fs.c.DataDirectory, user) // the root doesn't have a parent - _, err = fs.filecache.InsertOrUpdate(storageID, data, allowEmptyParent) + _, err = fs.filecache.InsertOrUpdate(ctx, storageID, data, allowEmptyParent) if err != nil { return err } @@ -774,11 +774,11 @@ func (fs *owncloudsqlfs) CreateDir(ctx context.Context, ref *provider.Reference) "mtime": mtime, "storage_mtime": mtime, } - storageID, err := fs.getStorage(ip) + storageID, err := fs.getStorage(ctx, ip) if err != nil { return err } - _, err = fs.filecache.InsertOrUpdate(storageID, data, false) + _, err = fs.filecache.InsertOrUpdate(ctx, storageID, data, false) if err != nil { if err != nil { return err @@ -1136,13 +1136,13 @@ func (fs *owncloudsqlfs) trash(ctx context.Context, ip string, rp string, origin } } - storage, err := fs.getStorage(ip) + storage, err := fs.getStorage(ctx, ip) if err != nil { return err } tryDelete := func() error { - return fs.filecache.Delete(storage, fs.getOwner(ip), fs.toDatabasePath(ip), fs.toDatabasePath(tgt)) + return fs.filecache.Delete(ctx, storage, fs.getOwner(ip), fs.toDatabasePath(ip), fs.toDatabasePath(tgt)) } err = tryDelete() if err != nil { @@ -1177,7 +1177,7 @@ func (fs *owncloudsqlfs) trashVersions(ctx context.Context, ip string, origin st // Ignore error since the only possible error is malformed pattern. versions, _ := filepath.Glob(vp + ".v*") - storage, err := fs.getStorage(ip) + storage, err := fs.getStorage(ctx, ip) if err != nil { return err } @@ -1196,7 +1196,7 @@ func (fs *owncloudsqlfs) trashVersions(ctx context.Context, ip string, origin st if err != nil { return errors.Wrap(err, "owncloudsql: error deleting file "+v) } - err = fs.filecache.Move(storage, fs.toDatabasePath(v), fs.toDatabasePath(tgt)) + err = fs.filecache.Move(ctx, storage, fs.toDatabasePath(v), fs.toDatabasePath(tgt)) if err != nil { return errors.Wrap(err, "owncloudsql: error deleting file "+v) } @@ -1228,11 +1228,11 @@ func (fs *owncloudsqlfs) Move(ctx context.Context, oldRef, newRef *provider.Refe } // TODO check target permissions ... if it exists - storage, err := fs.getStorage(oldIP) + storage, err := fs.getStorage(ctx, oldIP) if err != nil { return err } - err = fs.filecache.Move(storage, fs.toDatabasePath(oldIP), fs.toDatabasePath(newIP)) + err = fs.filecache.Move(ctx, storage, fs.toDatabasePath(oldIP), fs.toDatabasePath(newIP)) if err != nil { return err } @@ -1280,11 +1280,11 @@ func (fs *owncloudsqlfs) GetMD(ctx context.Context, ref *provider.Reference, mdK return nil, errors.Wrap(err, "owncloudsql: error reading permissions") } - ownerStorageID, err := fs.filecache.GetNumericStorageID("home::" + fs.getOwner(ip)) + ownerStorageID, err := fs.filecache.GetNumericStorageID(ctx, "home::"+fs.getOwner(ip)) if err != nil { return nil, err } - entry, err := fs.filecache.Get(ownerStorageID, fs.toDatabasePath(ip)) + entry, err := fs.filecache.Get(ctx, ownerStorageID, fs.toDatabasePath(ip)) switch { case err == sql.ErrNoRows: return nil, errtypes.NotFound(fs.toStoragePath(ctx, filepath.Dir(ip))) @@ -1338,11 +1338,11 @@ func (fs *owncloudsqlfs) listWithNominalHome(ctx context.Context, ip string, mdK return nil, errors.Wrap(err, "owncloudsql: error reading permissions") } - storage, err := fs.getStorage(ip) + storage, err := fs.getStorage(ctx, ip) if err != nil { return nil, err } - entries, err := fs.filecache.List(storage, fs.toDatabasePath(ip)+"/") + entries, err := fs.filecache.List(ctx, storage, fs.toDatabasePath(ip)+"/") if err != nil { return nil, errors.Wrapf(err, "owncloudsql: error listing %s", ip) } @@ -1389,11 +1389,11 @@ func (fs *owncloudsqlfs) listHome(ctx context.Context, home string, mdKeys []str return nil, errors.Wrap(err, "owncloudsql: error reading permissions") } - storage, err := fs.getStorage(ip) + storage, err := fs.getStorage(ctx, ip) if err != nil { return nil, err } - entries, err := fs.filecache.List(storage, fs.toDatabasePath(ip)+"/") + entries, err := fs.filecache.List(ctx, storage, fs.toDatabasePath(ip)+"/") if err != nil { return nil, errors.Wrapf(err, "owncloudsql: error listing %s", ip) } @@ -1422,7 +1422,7 @@ func (fs *owncloudsqlfs) archiveRevision(ctx context.Context, vbp string, ip str return errors.Wrap(err, "owncloudsql: error renaming from "+ip+" to "+vp) } - storage, err := fs.getStorage(ip) + storage, err := fs.getStorage(ctx, ip) if err != nil { return err } @@ -1433,7 +1433,7 @@ func (fs *owncloudsqlfs) archiveRevision(ctx context.Context, vbp string, ip str walkPath := "" for i := 0; i < len(parts); i++ { walkPath = filepath.Join(walkPath, parts[i]) - _, err := fs.filecache.Get(storage, walkPath) + _, err := fs.filecache.Get(ctx, storage, walkPath) if err == nil { continue } @@ -1449,12 +1449,12 @@ func (fs *owncloudsqlfs) archiveRevision(ctx context.Context, vbp string, ip str "permissions": 31, // 1: READ, 2: UPDATE, 4: CREATE, 8: DELETE, 16: SHARE } - _, err = fs.filecache.InsertOrUpdate(storage, data, false) + _, err = fs.filecache.InsertOrUpdate(ctx, storage, data, false) if err != nil { return errors.Wrap(err, "could not create parent version directory") } } - _, err = fs.filecache.Copy(storage, fs.toDatabasePath(ip), vdp) + _, err = fs.filecache.Copy(ctx, storage, fs.toDatabasePath(ip), vdp) return err } @@ -1506,11 +1506,11 @@ func (fs *owncloudsqlfs) ListRevisions(ctx context.Context, ref *provider.Refere vp := fs.getVersionsPath(ctx, ip) bn := filepath.Base(ip) - storageID, err := fs.getStorage(ip) + storageID, err := fs.getStorage(ctx, ip) if err != nil { return nil, err } - entries, err := fs.filecache.List(storageID, filepath.Dir(fs.toDatabasePath(vp))+"/") + entries, err := fs.filecache.List(ctx, storageID, filepath.Dir(fs.toDatabasePath(vp))+"/") if err != nil { return nil, err } @@ -1613,11 +1613,11 @@ func (fs *owncloudsqlfs) RestoreRevision(ctx context.Context, ref *provider.Refe "mtime": mtime, "storage_mtime": mtime, } - storageID, err := fs.getStorage(ip) + storageID, err := fs.getStorage(ctx, ip) if err != nil { return err } - _, err = fs.filecache.InsertOrUpdate(storageID, data, false) + _, err = fs.filecache.InsertOrUpdate(ctx, storageID, data, false) if err != nil { return err } @@ -1657,7 +1657,7 @@ func (fs *owncloudsqlfs) PurgeRecycleItem(ctx context.Context, ref *provider.Ref if err != nil { return err } - err = fs.filecache.PurgeRecycleItem(ctxpkg.ContextMustGetUser(ctx).Username, base, ttime, false) + err = fs.filecache.PurgeRecycleItem(ctx, ctxpkg.ContextMustGetUser(ctx).Username, base, ttime, false) if err != nil { return err } @@ -1667,7 +1667,7 @@ func (fs *owncloudsqlfs) PurgeRecycleItem(ctx context.Context, ref *provider.Ref if err != nil { return errors.Wrap(err, "owncloudsql: error listing recycle item versions") } - storageID, err := fs.getStorage(ip) + storageID, err := fs.getStorage(ctx, ip) if err != nil { return err } @@ -1676,7 +1676,7 @@ func (fs *owncloudsqlfs) PurgeRecycleItem(ctx context.Context, ref *provider.Ref if err != nil { return errors.Wrap(err, "owncloudsql: error deleting recycle item versions") } - err = fs.filecache.Purge(storageID, fs.toDatabasePath(versionFile)) + err = fs.filecache.Purge(ctx, storageID, fs.toDatabasePath(versionFile)) if err != nil { return err } @@ -1702,7 +1702,7 @@ func (fs *owncloudsqlfs) EmptyRecycle(ctx context.Context, ref *provider.Referen } u := ctxpkg.ContextMustGetUser(ctx) - err = fs.filecache.EmptyRecycle(u.Username) + err = fs.filecache.EmptyRecycle(ctx, u.Username) if err != nil { return errors.Wrap(err, "owncloudsql: error deleting recycle items from the database") } @@ -1733,7 +1733,7 @@ func (fs *owncloudsqlfs) convertToRecycleItem(ctx context.Context, md os.FileInf } u := ctxpkg.ContextMustGetUser(ctx) - item, err := fs.filecache.GetRecycleItem(u.Username, base, ttime) + item, err := fs.filecache.GetRecycleItem(ctx, u.Username, base, ttime) if err != nil { log := appctx.GetLogger(ctx) log.Error().Err(err).Str("path", md.Name()).Msg("could not get trash item") @@ -1802,7 +1802,7 @@ func (fs *owncloudsqlfs) RestoreRecycleItem(ctx context.Context, ref *provider.R if restoreRef.Path == "" { u := ctxpkg.ContextMustGetUser(ctx) - item, err := fs.filecache.GetRecycleItem(u.Username, base, ttime) + item, err := fs.filecache.GetRecycleItem(ctx, u.Username, base, ttime) if err != nil { log := appctx.GetLogger(ctx) log.Error().Err(err).Str("path", key).Msg("could not get trash item") @@ -1818,15 +1818,15 @@ func (fs *owncloudsqlfs) RestoreRecycleItem(ctx context.Context, ref *provider.R return errors.Wrap(err, "owncloudsql: could not restore item") } - storage, err := fs.getStorage(src) + storage, err := fs.getStorage(ctx, src) if err != nil { return err } - err = fs.filecache.Move(storage, fs.toDatabasePath(src), fs.toDatabasePath(tgt)) + err = fs.filecache.Move(ctx, storage, fs.toDatabasePath(src), fs.toDatabasePath(tgt)) if err != nil { return err } - err = fs.filecache.DeleteRecycleItem(ctxpkg.ContextMustGetUser(ctx).Username, base, ttime) + err = fs.filecache.DeleteRecycleItem(ctx, ctxpkg.ContextMustGetUser(ctx).Username, base, ttime) if err != nil { return err } @@ -1843,7 +1843,7 @@ func (fs *owncloudsqlfs) RestoreRecycleItemVersions(ctx context.Context, key, ta if err != nil { return fmt.Errorf("invalid trash item suffix") } - storage, err := fs.getStorage(target) + storage, err := fs.getStorage(ctx, target) if err != nil { return err } @@ -1869,7 +1869,7 @@ func (fs *owncloudsqlfs) RestoreRecycleItemVersions(ctx context.Context, key, ta if err = os.Rename(versionFile, versionsRestorePath); err != nil { return errors.Wrap(err, "owncloudsql: could not restore version file") } - err = fs.filecache.Move(storage, fs.toDatabasePath(versionFile), fs.toDatabasePath(versionsRestorePath)) + err = fs.filecache.Move(ctx, storage, fs.toDatabasePath(versionFile), fs.toDatabasePath(versionsRestorePath)) if err != nil { return err } @@ -1906,7 +1906,7 @@ func (fs *owncloudsqlfs) propagate(ctx context.Context, leafPath string) error { return err } - storageID, err := fs.getStorage(leafPath) + storageID, err := fs.getStorage(ctx, leafPath) if err != nil { return err } @@ -1936,7 +1936,7 @@ func (fs *owncloudsqlfs) propagate(ctx context.Context, leafPath string) error { return err } etag := calcEtag(ctx, fi) - if err := fs.filecache.SetEtag(storageID, fs.toDatabasePath(currentPath), etag); err != nil { + if err := fs.filecache.SetEtag(ctx, storageID, fs.toDatabasePath(currentPath), etag); err != nil { appctx.GetLogger(ctx).Error(). Err(err). Str("leafPath", leafPath). diff --git a/pkg/storage/fs/owncloudsql/spaces.go b/pkg/storage/fs/owncloudsql/spaces.go index c19e779d92..9b07348b9c 100644 --- a/pkg/storage/fs/owncloudsql/spaces.go +++ b/pkg/storage/fs/owncloudsql/spaces.go @@ -61,7 +61,7 @@ func (fs *owncloudsqlfs) ListStorageSpaces(ctx context.Context, filter []*provid if !ok { return nil, errtypes.UserRequired("error getting user from context") } - space, err := fs.getPersonalSpace(u) + space, err := fs.getPersonalSpace(ctx, u) if err != nil { return nil, err } @@ -113,16 +113,16 @@ func (fs *owncloudsqlfs) DeleteStorageSpace(ctx context.Context, req *provider.D // return spaces, nil // } -func (fs *owncloudsqlfs) getPersonalSpace(owner *userpb.User) (*provider.StorageSpace, error) { - storageID, err := fs.filecache.GetNumericStorageID("home::" + owner.Username) +func (fs *owncloudsqlfs) getPersonalSpace(ctx context.Context, owner *userpb.User) (*provider.StorageSpace, error) { + storageID, err := fs.filecache.GetNumericStorageID(ctx, "home::"+owner.Username) if err != nil { return nil, err } - storage, err := fs.filecache.GetStorage(storageID) + storage, err := fs.filecache.GetStorage(ctx, storageID) if err != nil { return nil, err } - root, err := fs.filecache.Get(storage.NumericID, "") + root, err := fs.filecache.Get(ctx, storage.NumericID, "") if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (fs *owncloudsqlfs) getPersonalSpace(owner *userpb.User) (*provider.Storage } func (fs *owncloudsqlfs) getSpaceByNumericID(ctx context.Context, spaceID int) (*provider.StorageSpace, error) { - storage, err := fs.filecache.GetStorage(spaceID) + storage, err := fs.filecache.GetStorage(ctx, spaceID) if err != nil { return nil, err } @@ -154,7 +154,7 @@ func (fs *owncloudsqlfs) getSpaceByNumericID(ctx context.Context, spaceID int) ( } func (fs *owncloudsqlfs) storageToSpace(ctx context.Context, storage *filecache.Storage) (*provider.StorageSpace, error) { - root, err := fs.filecache.Get(storage.NumericID, "") + root, err := fs.filecache.Get(ctx, storage.NumericID, "") if err != nil { return nil, err } diff --git a/pkg/storage/fs/owncloudsql/upload.go b/pkg/storage/fs/owncloudsql/upload.go index 47bcd16af6..f3406917ab 100644 --- a/pkg/storage/fs/owncloudsql/upload.go +++ b/pkg/storage/fs/owncloudsql/upload.go @@ -191,7 +191,7 @@ func (fs *owncloudsqlfs) NewUpload(ctx context.Context, info tusd.FileInfo) (upl return nil, errors.Wrap(err, "owncloudsql: error resolving upload path") } usr := ctxpkg.ContextMustGetUser(ctx) - storageID, err := fs.getStorage(ip) + storageID, err := fs.getStorage(ctx, ip) if err != nil { return nil, err } @@ -405,7 +405,7 @@ func (upload *fileUpload) FinishUpload(ctx context.Context) error { "mtime": upload.info.MetaData["mtime"], "storage_mtime": upload.info.MetaData["mtime"], } - _, err = upload.fs.filecache.InsertOrUpdate(upload.info.Storage["StorageId"], data, false) + _, err = upload.fs.filecache.InsertOrUpdate(ctx, upload.info.Storage["StorageId"], data, false) if err != nil { return err } diff --git a/pkg/user/manager/owncloudsql/accounts/accounts.go b/pkg/user/manager/owncloudsql/accounts/accounts.go index 4ec8ef3afc..f80947e415 100644 --- a/pkg/user/manager/owncloudsql/accounts/accounts.go +++ b/pkg/user/manager/owncloudsql/accounts/accounts.go @@ -42,8 +42,11 @@ func NewMysql(dsn string, joinUsername, joinUUID, enableMedialSearch bool) (*Acc if err != nil { return nil, errors.Wrap(err, "error connecting to the database") } + + // FIXME make configurable sqldb.SetConnMaxLifetime(time.Minute * 3) - sqldb.SetMaxOpenConns(10) + sqldb.SetConnMaxIdleTime(time.Second * 30) + sqldb.SetMaxOpenConns(100) sqldb.SetMaxIdleConns(10) err = sqldb.Ping()