internal: remove unit-meta-with-latest experiment

For golang/go#43265

Change-Id: I1d056a893fdff60744ff328ab9f4a1b6665b3e32
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/309709
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
This commit is contained in:
Jonathan Amsterdam 2021-04-13 09:25:43 -04:00
Родитель 58432cb4a0
Коммит 103f9ede54
3 изменённых файлов: 11 добавлений и 245 удалений

Просмотреть файл

@ -9,7 +9,6 @@ const (
ExperimentInsertSymbols = "insert-symbols" ExperimentInsertSymbols = "insert-symbols"
ExperimentSymbolHistoryVersionsPage = "symbol-history-versions-page" ExperimentSymbolHistoryVersionsPage = "symbol-history-versions-page"
ExperimentSymbolHistoryMainPage = "symbol-history-main-page" ExperimentSymbolHistoryMainPage = "symbol-history-main-page"
ExperimentUnitMetaWithLatest = "unit-meta-with-latest"
) )
// Experiments represents all of the active experiments in the codebase and // Experiments represents all of the active experiments in the codebase and
@ -18,7 +17,6 @@ var Experiments = map[string]string{
ExperimentInsertSymbols: "Insert data into symbols, package_symbols, and documentation_symbols.", ExperimentInsertSymbols: "Insert data into symbols, package_symbols, and documentation_symbols.",
ExperimentSymbolHistoryVersionsPage: "Show package API history on the versions page.", ExperimentSymbolHistoryVersionsPage: "Show package API history on the versions page.",
ExperimentSymbolHistoryMainPage: "Show package API history on the main unit page.", ExperimentSymbolHistoryMainPage: "Show package API history on the main unit page.",
ExperimentUnitMetaWithLatest: "Use latest-version information for GetUnitMeta.",
} }
// Experiment holds data associated with an experimental feature for frontend // Experiment holds data associated with an experimental feature for frontend

Просмотреть файл

@ -16,7 +16,6 @@ import (
"golang.org/x/pkgsite/internal" "golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/database" "golang.org/x/pkgsite/internal/database"
"golang.org/x/pkgsite/internal/derrors" "golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/experiment"
"golang.org/x/pkgsite/internal/middleware" "golang.org/x/pkgsite/internal/middleware"
"golang.org/x/pkgsite/internal/stdlib" "golang.org/x/pkgsite/internal/stdlib"
"golang.org/x/pkgsite/internal/version" "golang.org/x/pkgsite/internal/version"
@ -39,19 +38,16 @@ func (db *DB) GetUnitMeta(ctx context.Context, fullPath, requestedModulePath, re
defer derrors.WrapStack(&err, "DB.GetUnitMeta(ctx, %q, %q, %q)", fullPath, requestedModulePath, requestedVersion) defer derrors.WrapStack(&err, "DB.GetUnitMeta(ctx, %q, %q, %q)", fullPath, requestedModulePath, requestedVersion)
defer middleware.ElapsedStat(ctx, "GetUnitMeta")() defer middleware.ElapsedStat(ctx, "GetUnitMeta")()
if experiment.IsActive(ctx, internal.ExperimentUnitMetaWithLatest) { modulePath := requestedModulePath
modulePath := requestedModulePath version := requestedVersion
version := requestedVersion var lmv *internal.LatestModuleVersions
var lmv *internal.LatestModuleVersions if requestedVersion == internal.LatestVersion {
if requestedVersion == internal.LatestVersion { modulePath, version, lmv, err = db.getLatestUnitVersion(ctx, fullPath, requestedModulePath)
modulePath, version, lmv, err = db.getLatestUnitVersion(ctx, fullPath, requestedModulePath) if err != nil {
if err != nil { return nil, err
return nil, err
}
} }
return db.getUnitMetaWithKnownLatestVersion(ctx, fullPath, modulePath, version, lmv)
} }
return db.legacyGetUnitMeta(ctx, fullPath, requestedModulePath, requestedVersion) return db.getUnitMetaWithKnownLatestVersion(ctx, fullPath, modulePath, version, lmv)
} }
func (db *DB) getUnitMetaWithKnownLatestVersion(ctx context.Context, fullPath, modulePath, version string, lmv *internal.LatestModuleVersions) (_ *internal.UnitMeta, err error) { func (db *DB) getUnitMetaWithKnownLatestVersion(ctx context.Context, fullPath, modulePath, version string, lmv *internal.LatestModuleVersions) (_ *internal.UnitMeta, err error) {
@ -225,131 +221,6 @@ func (db *DB) getLatestUnitVersion(ctx context.Context, fullPath, requestedModul
return modulePath, latestVersion, nil, nil return modulePath, latestVersion, nil, nil
} }
func (db *DB) legacyGetUnitMeta(ctx context.Context, fullPath, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
defer derrors.WrapStack(&err, "DB.legacyGetUnitMeta(ctx, %q, %q, %q)", fullPath, requestedModulePath, requestedVersion)
var (
q string
args []interface{}
)
q, args, err = getUnitMetaQuery(fullPath, requestedModulePath, requestedVersion).PlaceholderFormat(squirrel.Dollar).ToSql()
if err != nil {
return nil, fmt.Errorf("squirrel.ToSql: %v", err)
}
var (
licenseTypes []string
licensePaths []string
um = internal.UnitMeta{Path: fullPath}
)
err = db.db.QueryRow(ctx, q, args...).Scan(
&um.ModulePath,
&um.Version,
&um.CommitTime,
jsonbScanner{&um.SourceInfo},
&um.HasGoMod,
&um.ModuleInfo.IsRedistributable,
&um.Name,
&um.IsRedistributable,
pq.Array(&licenseTypes),
pq.Array(&licensePaths))
switch err {
case sql.ErrNoRows:
return nil, derrors.NotFound
case nil:
lics, err := zipLicenseMetadata(licenseTypes, licensePaths)
if err != nil {
return nil, err
}
if db.bypassLicenseCheck {
um.IsRedistributable = true
}
um.Licenses = lics
if err := populateLatestInfo(ctx, db, &um.ModuleInfo); err != nil {
return nil, err
}
return &um, nil
default:
return nil, err
}
}
func getUnitMetaQuery(fullPath, requestedModulePath, requestedVersion string) squirrel.SelectBuilder {
query := squirrel.Select(
"m.module_path",
"m.version",
"m.commit_time",
"m.source_info",
"m.has_go_mod",
"m.redistributable",
"u.name",
"u.redistributable",
"u.license_types",
"u.license_paths",
)
if requestedVersion != internal.LatestVersion {
query = query.From("modules m").
Join("units u on u.module_id = m.id").
Join("paths p ON p.id = u.path_id").Where(squirrel.Eq{"p.path": fullPath})
if requestedModulePath != internal.UnknownModulePath {
query = query.Where(squirrel.Eq{"m.module_path": requestedModulePath})
}
if internal.DefaultBranches[requestedVersion] {
query = query.Join("version_map vm ON m.id = vm.module_id").Where("vm.requested_version = ? ", requestedVersion)
} else if requestedVersion != internal.LatestVersion {
query = query.Where(squirrel.Eq{"version": requestedVersion})
}
return orderByLatest(query).Limit(1)
}
// Use a nested select to fetch the latest version of the unit, then JOIN
// on units to fetch other relevant information. This allows us to use the
// index on units.id and paths.path to get the latest path. We can then
// look up only the relevant information from the units table.
nestedSelect := orderByLatest(squirrel.Select(
"m.id",
"m.module_path",
"m.version",
"m.commit_time",
"m.source_info",
"m.has_go_mod",
"m.redistributable",
"u.id AS unit_id",
).From("modules m").
Join("units u ON u.module_id = m.id").
Join("paths p ON p.id = u.path_id").
Where(squirrel.Eq{"p.path": fullPath}))
if requestedModulePath != internal.UnknownModulePath {
nestedSelect = nestedSelect.Where(squirrel.Eq{"m.module_path": requestedModulePath})
}
nestedSelect = nestedSelect.Limit(1)
return query.From("units u").JoinClause(nestedSelect.Prefix("JOIN (").Suffix(") m ON u.id = m.unit_id"))
}
// orderByLatest orders paths according to the go command.
// Versions are ordered by:
// (1) release (non-incompatible)
// (2) prerelease (non-incompatible)
// (3) release, incompatible
// (4) prerelease, incompatible
// (5) pseudo
// They are then sorted based on semver, then decreasing module path length (so
// that nested modules are preferred).
func orderByLatest(q squirrel.SelectBuilder) squirrel.SelectBuilder {
return q.OrderBy(
`CASE
WHEN m.version_type = 'release' AND NOT m.incompatible THEN 1
WHEN m.version_type = 'prerelease' AND NOT m.incompatible THEN 2
WHEN m.version_type = 'release' THEN 3
WHEN m.version_type = 'prerelease' THEN 4
ELSE 5
END`,
"m.series_path DESC",
"m.sort_version DESC",
).PlaceholderFormat(squirrel.Dollar)
}
// GetUnit returns a unit from the database, along with all of the data // GetUnit returns a unit from the database, along with all of the data
// associated with that unit. // associated with that unit.
func (db *DB) GetUnit(ctx context.Context, um *internal.UnitMeta, fields internal.FieldSet) (_ *internal.Unit, err error) { func (db *DB) GetUnit(ctx context.Context, um *internal.UnitMeta, fields internal.FieldSet) (_ *internal.Unit, err error) {

Просмотреть файл

@ -26,12 +26,7 @@ func TestGetUnitMeta(t *testing.T) {
t.Parallel() t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testTimeout*2) ctx, cancel := context.WithTimeout(context.Background(), testTimeout*2)
defer cancel() defer cancel()
t.Run("legacy", func(t *testing.T) { testGetUnitMeta(t, ctx)
testGetUnitMeta(t, ctx)
})
t.Run("latest", func(t *testing.T) {
testGetUnitMeta(t, experiment.NewContext(ctx, internal.ExperimentUnitMetaWithLatest))
})
} }
func testGetUnitMeta(t *testing.T, ctx context.Context) { func testGetUnitMeta(t *testing.T, ctx context.Context) {
@ -207,104 +202,6 @@ func testGetUnitMeta(t *testing.T, ctx context.Context) {
} }
} }
func TestGetUnitMetaDiffs(t *testing.T) {
// Demonstrate differences between legacy and latest-version GetUnitMeta
// implementations.
t.Parallel()
type latest struct { // latest-version info
module string
version string // latest raw and cooked version
goMod string // go.mod file contents after "module" line
}
modver := func(u *internal.UnitMeta) string { return u.ModulePath + "@" + u.Version }
for _, test := range []struct {
name string
packages []string // mod@ver/pkg
latests []latest
path string
wantLatest, wantLegacy string
}{
{
name: "incompatible",
// When there are incompatible versions and no go.mod at the latest
// compatible version, the go command selects the highest
// incompatible version, but legacy GetUnitMeta selects the highest
// compatible version.
packages: []string{
"m.com@v1.0.0/a",
"m.com@v2.0.0+incompatible/a",
},
latests: []latest{{"m.com", "v2.0.0+incompatible", ""}},
path: "m.com/a",
wantLatest: "m.com@v2.0.0+incompatible",
wantLegacy: "m.com@v1.0.0",
},
{
name: "shorter",
// The go command prefers the longer path if both have latest-version information,
// but legacy GetUnitMeta prefers the shorter path if it has a release version.
packages: []string{
"m.com@v1.0.0/a/b", // shorter path, release version
"m.com/a@v1.0.0-pre/b", // longer path, pre-release version
},
latests: []latest{{"m.com", "v1.0.0", ""}, {"m.com/a", "v1.0.0-pre", ""}},
path: "m.com/a/b",
wantLatest: "m.com/a@v1.0.0-pre",
wantLegacy: "m.com@v1.0.0",
},
{
name: "retraction",
// Legacy GetUnitMeta ignores retractions when picking the latest version.
packages: []string{
"m.com@v1.0.0/a",
"m.com@v1.1.0/a", // latest, also retracted
},
latests: []latest{{"m.com", "v1.1.0", "retract v1.1.0"}},
path: "m.com/a",
wantLatest: "m.com@v1.0.0",
wantLegacy: "m.com@v1.1.0",
},
} {
t.Run(test.name, func(t *testing.T) {
ctx := context.Background()
testDB, release := acquire(t)
defer release()
for _, p := range test.packages {
mod, ver, pkg := parseModuleVersionPackage(p)
m := sample.Module(mod, ver, pkg)
goMod := "module " + mod
for _, l := range test.latests {
if l.module == mod && l.version == ver {
goMod += "\n" + l.goMod
break
}
}
MustInsertModuleGoMod(ctx, t, testDB, m, goMod)
}
gotLegacy, err := testDB.GetUnitMeta(ctx, test.path, internal.UnknownModulePath, internal.LatestVersion)
if err != nil {
t.Fatal(err)
}
if got := modver(gotLegacy); got != test.wantLegacy {
t.Errorf("legacy: got %s, want %s", got, test.wantLegacy)
}
gotLatest, err := testDB.GetUnitMeta(experiment.NewContext(ctx, internal.ExperimentUnitMetaWithLatest),
test.path, internal.UnknownModulePath, internal.LatestVersion)
if err != nil {
t.Fatal(err)
}
if got := modver(gotLatest); got != test.wantLatest {
t.Errorf("latest: got %s, want %s", got, test.wantLatest)
}
})
}
}
func TestGetUnitMetaBypass(t *testing.T) { func TestGetUnitMetaBypass(t *testing.T) {
t.Parallel() t.Parallel()
testDB, release := acquire(t) testDB, release := acquire(t)
@ -318,13 +215,13 @@ func TestGetUnitMetaBypass(t *testing.T) {
module, version, packageSuffix string module, version, packageSuffix string
isMaster bool isMaster bool
}{ }{
{"m.com", "v2.0.0+incompatible", "a", false},
{"m.com/b", "v2.0.0+incompatible", "a", true},
{"m.com", "v1.0.0", "a", false}, {"m.com", "v1.0.0", "a", false},
{"m.com", "v1.0.1", "dir/a", false}, {"m.com", "v1.0.1", "dir/a", false},
{"m.com", "v1.1.0", "a/b", false}, {"m.com", "v1.1.0", "a/b", false},
{"m.com", "v1.2.0-pre", "a", true}, {"m.com", "v1.2.0-pre", "a", true},
{"m.com", "v2.0.0+incompatible", "a", false},
{"m.com/a", "v1.1.0", "b", false}, {"m.com/a", "v1.1.0", "b", false},
{"m.com/b", "v2.0.0+incompatible", "a", true},
} { } {
m := sample.Module(testModule.module, testModule.version, testModule.packageSuffix) m := sample.Module(testModule.module, testModule.version, testModule.packageSuffix)
makeModuleNonRedistributable(m) makeModuleNonRedistributable(m)