Naming, layout and comments: descriptive full-word names, one item per line in wrapped calls and literals, and doc comments on exported names
Short and single-letter names in application code become full words (tests keep theirs). Wrapped calls, signatures and composite literals put one item per line, and one-line function bodies are expanded. Exported names and groups of constants get doc comments, and comments refer to the renamed identifiers.
This commit is contained in:
1 parent
043e307663
commit
465358609a
78 files changed
+2374
-1402
No files matched your search
@@ -43,7 +43,7 @@ type Store struct {
|
||||
// left incomplete by a crash is ended so new ones start on a fresh line.
|
||||
// It logs to slog.Default() unless given WithLogger.
|
||||
func OpenStore(path string, opts ...Option) (*Store, error) {
|
||||
s := &Store{
|
||||
store := &Store{
|
||||
latest: map[string]int{},
|
||||
lastNum: map[int]int{},
|
||||
openPos: map[string]int{},
|
||||
@@ -53,57 +53,57 @@ func OpenStore(path string, opts ...Option) (*Store, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
releases, err := readReleases(s.opts.logger("store"), path)
|
||||
releases, err := readReleases(store.opts.logger("store"), path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The file is written in order, but sort anyway in case it was hand-edited.
|
||||
sort.SliceStable(releases, func(i, j int) bool {
|
||||
return releases[i].Date.Before(releases[j].Date)
|
||||
sort.SliceStable(releases, func(i, other int) bool {
|
||||
return releases[i].Date.Before(releases[other].Date)
|
||||
})
|
||||
for _, r := range releases {
|
||||
s.releases = append(s.releases, r)
|
||||
s.times = append(s.times, r.Date)
|
||||
for _, release := range releases {
|
||||
store.releases = append(store.releases, release)
|
||||
store.times = append(store.times, release.Date)
|
||||
}
|
||||
for i, r := range s.releases {
|
||||
s.index(i, r)
|
||||
for i, release := range store.releases {
|
||||
store.index(i, release)
|
||||
}
|
||||
|
||||
if s.f, err = openForAppend(path); err != nil {
|
||||
if store.f, err = openForAppend(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
return store, nil
|
||||
}
|
||||
|
||||
// readReleases reads the releases stored at path, skipping blank lines and
|
||||
// lines that can't be decoded (which are logged to logger). A missing file
|
||||
// holds no releases.
|
||||
func readReleases(logger *slog.Logger, path string) ([]ocds.Release, error) {
|
||||
in, err := os.Open(filepath.Clean(path))
|
||||
input, err := os.Open(filepath.Clean(path))
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer in.Close() //nolint:errcheck // read only
|
||||
defer input.Close() //nolint:errcheck // read only
|
||||
|
||||
var releases []ocds.Release
|
||||
sc := bufio.NewScanner(in)
|
||||
sc.Buffer(make([]byte, 1<<20), 64<<20)
|
||||
for line := 1; sc.Scan(); line++ {
|
||||
b := bytes.TrimSpace(sc.Bytes())
|
||||
if len(b) == 0 {
|
||||
scanner := bufio.NewScanner(input)
|
||||
scanner.Buffer(make([]byte, 1<<20), 64<<20)
|
||||
for line := 1; scanner.Scan(); line++ {
|
||||
data := bytes.TrimSpace(scanner.Bytes())
|
||||
if len(data) == 0 {
|
||||
continue
|
||||
}
|
||||
var r ocds.Release
|
||||
if err := json.Unmarshal(b, &r); err != nil {
|
||||
var release ocds.Release
|
||||
if err := json.Unmarshal(data, &release); err != nil {
|
||||
logger.Warn("skipping unreadable line", "line", line, "error", err)
|
||||
continue
|
||||
}
|
||||
releases = append(releases, r)
|
||||
releases = append(releases, release)
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("reading %s: %w", path, err)
|
||||
}
|
||||
return releases, nil
|
||||
@@ -113,60 +113,60 @@ func readReleases(logger *slog.Logger, path string) ([]ocds.Release, error) {
|
||||
// mid-write, it ends the partial record so the next one starts on a fresh
|
||||
// line.
|
||||
func openForAppend(path string) (*os.File, error) {
|
||||
f, err := os.OpenFile(filepath.Clean(path), os.O_CREATE|os.O_RDWR|os.O_APPEND, 0o600)
|
||||
file, err := os.OpenFile(filepath.Clean(path), os.O_CREATE|os.O_RDWR|os.O_APPEND, 0o600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if st, err := f.Stat(); err == nil && st.Size() > 0 {
|
||||
if info, err := file.Stat(); err == nil && info.Size() > 0 {
|
||||
last := make([]byte, 1)
|
||||
if _, err := f.ReadAt(last, st.Size()-1); err == nil && last[0] != '\n' {
|
||||
if _, err := f.Write([]byte("\n")); err != nil {
|
||||
return nil, errors.Join(fmt.Errorf("repairing %s: %w", path, err), f.Close())
|
||||
if _, err := file.ReadAt(last, info.Size()-1); err == nil && last[0] != '\n' {
|
||||
if _, err := file.Write([]byte("\n")); err != nil {
|
||||
return nil, errors.Join(fmt.Errorf("repairing %s: %w", path, err), file.Close())
|
||||
}
|
||||
}
|
||||
}
|
||||
return f, nil
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// index records release r, at position i, in the lookups: the ocid's latest
|
||||
// index records release, at position i, in the lookups: the ocid's latest
|
||||
// release, whether its procedure is still open (an award closes it), and the
|
||||
// highest notice number used each year.
|
||||
func (s *Store) index(i int, r ocds.Release) {
|
||||
s.latest[r.OCID] = i
|
||||
if len(r.Tag) > 0 && r.Tag[0] == "award" {
|
||||
s.closeProcedure(r.OCID)
|
||||
} else if _, ok := s.openPos[r.OCID]; !ok {
|
||||
s.openPos[r.OCID] = len(s.open)
|
||||
s.open = append(s.open, r.OCID)
|
||||
func (s *Store) index(i int, release ocds.Release) {
|
||||
s.latest[release.OCID] = i
|
||||
if len(release.Tag) > 0 && release.Tag[0] == "award" {
|
||||
s.closeProcedure(release.OCID)
|
||||
} else if _, ok := s.openPos[release.OCID]; !ok {
|
||||
s.openPos[release.OCID] = len(s.open)
|
||||
s.open = append(s.open, release.OCID)
|
||||
}
|
||||
if num, year, ok := strings.Cut(r.ID, "-"); ok {
|
||||
n, err1 := strconv.Atoi(num)
|
||||
y, err2 := strconv.Atoi(year)
|
||||
if err1 == nil && err2 == nil && n > s.lastNum[y] {
|
||||
s.lastNum[y] = n
|
||||
if numberText, year, ok := strings.Cut(release.ID, "-"); ok {
|
||||
number, numberErr := strconv.Atoi(numberText)
|
||||
yearNumber, yearErr := strconv.Atoi(year)
|
||||
if numberErr == nil && yearErr == nil && number > s.lastNum[yearNumber] {
|
||||
s.lastNum[yearNumber] = number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// closeProcedure removes ocid from the open procedures, if it is there.
|
||||
func (s *Store) closeProcedure(ocid string) {
|
||||
pos, ok := s.openPos[ocid]
|
||||
position, ok := s.openPos[ocid]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
last := len(s.open) - 1
|
||||
s.open[pos] = s.open[last]
|
||||
s.openPos[s.open[pos]] = pos
|
||||
s.open[position] = s.open[last]
|
||||
s.openPos[s.open[position]] = position
|
||||
s.open = s.open[:last]
|
||||
delete(s.openPos, ocid)
|
||||
}
|
||||
|
||||
// Append persists a release and flushes it to disk.
|
||||
func (s *Store) Append(r ocds.Release) error { return s.append(r, true) }
|
||||
func (s *Store) Append(release ocds.Release) error { return s.append(release, true) }
|
||||
|
||||
// AppendNoSync persists a release without an fsync; call Sync afterwards.
|
||||
// Used for bulk catch-up, where a sync per record would be very slow.
|
||||
func (s *Store) AppendNoSync(r ocds.Release) error { return s.append(r, false) }
|
||||
func (s *Store) AppendNoSync(release ocds.Release) error { return s.append(release, false) }
|
||||
|
||||
// Sync flushes appended releases to disk. Call it after AppendNoSync.
|
||||
func (s *Store) Sync() error {
|
||||
@@ -175,22 +175,22 @@ func (s *Store) Sync() error {
|
||||
return s.f.Sync()
|
||||
}
|
||||
|
||||
// append stores r, syncing the file to disk if sync is true. A date earlier
|
||||
// append stores release, syncing the file to disk if sync is true. A date earlier
|
||||
// than the newest stored release (for example after a clock change) is moved
|
||||
// up so the order stays valid.
|
||||
func (s *Store) append(r ocds.Release, sync bool) error {
|
||||
func (s *Store) append(release ocds.Release, sync bool) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
r.Date = r.Date.UTC()
|
||||
if n := len(s.times); n > 0 && r.Date.Before(s.times[n-1]) {
|
||||
r.Date = s.times[n-1]
|
||||
release.Date = release.Date.UTC()
|
||||
if count := len(s.times); count > 0 && release.Date.Before(s.times[count-1]) {
|
||||
release.Date = s.times[count-1]
|
||||
}
|
||||
b, err := json.Marshal(r)
|
||||
data, err := json.Marshal(release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := s.f.Write(append(b, '\n')); err != nil {
|
||||
if _, err := s.f.Write(append(data, '\n')); err != nil {
|
||||
return err
|
||||
}
|
||||
if sync {
|
||||
@@ -198,9 +198,9 @@ func (s *Store) append(r ocds.Release, sync bool) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
s.releases = append(s.releases, r)
|
||||
s.times = append(s.times, r.Date)
|
||||
s.index(len(s.releases)-1, r)
|
||||
s.releases = append(s.releases, release)
|
||||
s.times = append(s.times, release.Date)
|
||||
s.index(len(s.releases)-1, release)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -210,7 +210,9 @@ func (s *Store) Page(from, upper time.Time, start, limit int) ([]ocds.Release, i
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
i := sort.Search(len(s.times), func(i int) bool { return !s.times[i].Before(from) })
|
||||
i := sort.Search(len(s.times), func(i int) bool {
|
||||
return !s.times[i].Before(from)
|
||||
})
|
||||
if start > i {
|
||||
i = start
|
||||
}
|
||||
@@ -259,11 +261,11 @@ func (s *Store) NextNoticeID(year int) string {
|
||||
// RandomOpen picks a procedure that has not been awarded and whose latest
|
||||
// release is after since. Procedures idle since before then are dropped from
|
||||
// the open set, as if they had been abandoned.
|
||||
func (s *Store) RandomOpen(r *rand.Rand, since time.Time) (ocds.Release, bool) {
|
||||
func (s *Store) RandomOpen(rng *rand.Rand, since time.Time) (ocds.Release, bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for len(s.open) > 0 {
|
||||
ocid := s.open[r.Intn(len(s.open))]
|
||||
ocid := s.open[rng.Intn(len(s.open))]
|
||||
i := s.latest[ocid]
|
||||
if s.times[i].After(since) {
|
||||
return s.releases[i], true
|
||||
|
||||
Reference in new issue
Block a user