fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

1package main 2 3import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io/fs" 8 "log" 9 "os" 10 "time" 11) 12 13type ownerChangeError struct { 14 Path string 15 Owner, Current string 16} 17 18func (e *ownerChangeError) Error() string { 19 return fmt.Sprintf("detected a change of ownership of %s. In multiple replica setups this can lead to un-needed rebalancing or bugs if there are multiple writers: owner=%q current=%q", e.Path, e.Owner, e.Current) 20} 21 22// ownerChecker can write and check the owner file for a index directory. It 23// is used for detecting when multiple zoekts are writing to a directory, or 24// when the ownership is changing too often. 25// 26// The motivation for this is a person can misconfigure zoekt such that 27// multiple indexservers write to the same directory. This will lead to index 28// thrashing and hard to debug errors. Alternatively if the stable identity 29// (hostname) changes, this can lead to Sourcegraph's repo <-> owner hash 30// changing which means unnecessary rebalancing. 31type ownerChecker struct { 32 Path string 33 Hostname string 34} 35 36// Run will regularly init then regularly check if we are owner. If an error 37// is detected it will exit the current process with exit code 1. This method 38// blocks. 39func (o *ownerChecker) Run() { 40 if err := o.Init(); err != nil { 41 log.Fatal(err) 42 } 43 for { 44 time.Sleep(5 * time.Second) 45 if err := o.Check(); err != nil { 46 log.Fatal(err) 47 } 48 } 49} 50 51func (o *ownerChecker) Init() error { 52 var ownerErr *ownerChangeError 53 if err := o.Check(); errors.Is(err, fs.ErrNotExist) { 54 // do nothing, first run so we just write out the file 55 } else if errors.As(err, &ownerErr) { 56 debugLog.Printf("WARN: detected a change in ownership at startup. You can ignore this if you only have one zoekt replica: %s", err) 57 } else if err != nil { 58 return err 59 } 60 61 content := []byte(fmt.Sprintf(`DO NOT EDIT! generated by zoekt-sourcegraph-indexserver. 62This file records the identity of the owner of this zoekt index directory. 63If it changes, zoekt-sourcegraph-indexserver will exit with a non-zero exit code. 64This is to prevent multiple owners/writers. 65 66hostname=%s 67`, o.Hostname)) 68 69 // Always write out since we may update the comment 70 if err := os.WriteFile(o.Path, content, 0o600); err != nil { 71 return fmt.Errorf("failed to write owner file %s: %w", o.Path, err) 72 } 73 74 return nil 75} 76 77func (o *ownerChecker) Check() error { 78 if b, err := os.ReadFile(o.Path); err != nil { 79 return fmt.Errorf("failed to read in owner file %s: %w", o.Path, err) 80 } else if owner := bestEffortParseOwner(b); o.Hostname != owner { 81 return &ownerChangeError{ 82 Path: o.Path, 83 Owner: owner, 84 Current: o.Hostname, 85 } 86 } 87 return nil 88} 89 90func bestEffortParseOwner(b []byte) string { 91 prefix := []byte("hostname=") 92 from := bytes.Index(b, prefix) 93 if from < 0 { 94 return "UNKNOWN" 95 } 96 97 b = b[from+len(prefix):] 98 if to := bytes.IndexByte(b, '\n'); to > 0 { 99 b = b[:to] 100 } 101 102 return string(bytes.TrimSpace(b)) 103}