diff options
Diffstat (limited to 'doc/articles')
-rw-r--r-- | doc/articles/c_go_cgo.html | 9 | ||||
-rw-r--r-- | doc/articles/concurrency_patterns.html | 4 | ||||
-rw-r--r-- | doc/articles/error_handling.html | 2 | ||||
-rw-r--r-- | doc/articles/go_command.html | 4 | ||||
-rw-r--r-- | doc/articles/godoc_documenting_go_code.html | 18 | ||||
-rw-r--r-- | doc/articles/image_package.html | 8 | ||||
-rw-r--r-- | doc/articles/json_and_go.html | 23 | ||||
-rw-r--r-- | doc/articles/json_rpc_tale_of_interfaces.html | 2 | ||||
-rw-r--r-- | doc/articles/laws_of_reflection.html | 2 | ||||
-rw-r--r-- | doc/articles/race_detector.html | 369 | ||||
-rw-r--r-- | doc/articles/slices_usage_and_internals.html | 2 | ||||
-rw-r--r-- | doc/articles/wiki/get.go | 19 | ||||
-rw-r--r-- | doc/articles/wiki/index.html | 209 | ||||
-rw-r--r-- | doc/articles/wiki/part3-errorhandling.go | 75 | ||||
-rw-r--r-- | doc/articles/wiki/part3.go | 59 | ||||
-rwxr-xr-x | doc/articles/wiki/test.bash | 7 |
16 files changed, 670 insertions, 142 deletions
diff --git a/doc/articles/c_go_cgo.html b/doc/articles/c_go_cgo.html index ac6bb29a2..b37a6ba65 100644 --- a/doc/articles/c_go_cgo.html +++ b/doc/articles/c_go_cgo.html @@ -149,9 +149,9 @@ is more complex than a single function call), as in this rewrite of </p> <p> -To build cgo packages, just use <a href="/cmd/go/#Compile_packages_and_dependencies">" +To build cgo packages, just use <a href="/cmd/go/#hdr-Compile_packages_and_dependencies">" <code>go build</code>"</a> or -<a href="/cmd/go/#Compile_and_install_packages_and_dependencies">"<code>go install</code> +<a href="/cmd/go/#hdr-Compile_and_install_packages_and_dependencies">"<code>go install</code> "</a> as usual. The go tool recognizes the special <code>"C"</code> import and automatically uses cgo for those files. </p> @@ -169,9 +169,8 @@ in the Go tree demonstrate more advanced concepts. <p> For a simple, idiomatic example of a cgo-based package, see Russ Cox's <a href="http://code.google.com/p/gosqlite/source/browse/sqlite/sqlite.go">gosqlite</a>. -Also, the Go Project Dashboard lists <a -href="https://godashboard.appspot.com/project?tag=cgo">several other -cgo packages</a>. +Also, the <a href="http://code.google.com/p/go-wiki/wiki/Projects">Go Community Wiki</a> +lists many packages, some of which use cgo. </p> <p> diff --git a/doc/articles/concurrency_patterns.html b/doc/articles/concurrency_patterns.html index 63c8cd59e..62168b840 100644 --- a/doc/articles/concurrency_patterns.html +++ b/doc/articles/concurrency_patterns.html @@ -17,7 +17,7 @@ and launching a goroutine that sleeps before sending on the channel: We can then use a <code>select</code> statement to receive from either <code>ch</code> or <code>timeout</code>. If nothing arrives on <code>ch</code> after one second, the timeout case is selected and the attempt to read from -<cde>ch</cde> is abandoned. +<code>ch</code> is abandoned. </p> {{code "/doc/progs/timeout1.go" `/select {/` `/STOP/`}} @@ -64,7 +64,7 @@ could fail since no one is ready. </p> <p> -This problem is a textbook of example of what is known as a +This problem is a textbook example of what is known as a <a href="https://en.wikipedia.org/wiki/Race_condition">race condition</a>, but the fix is trivial. We just make sure to buffer the channel <code>ch</code> (by adding the buffer length as the second argument to <a href="/pkg/builtin/#make">make</a>), diff --git a/doc/articles/error_handling.html b/doc/articles/error_handling.html index 8f4fffb48..6ba05ac1d 100644 --- a/doc/articles/error_handling.html +++ b/doc/articles/error_handling.html @@ -137,7 +137,7 @@ messages: <p> (This is a slightly simplified version of some -<a href="http://camlistore.org/code/?p=camlistore.git;a=blob;f=lib/go/camli/jsonconfig/eval.go#l68">actual code</a> +<a href="http://golang.org/s/camjsondecode">actual code</a> from the <a href="http://camlistore.org">Camlistore</a> project.) </p> diff --git a/doc/articles/go_command.html b/doc/articles/go_command.html index 1e9e70fd8..fddca41e2 100644 --- a/doc/articles/go_command.html +++ b/doc/articles/go_command.html @@ -48,9 +48,9 @@ had to be installed in certain places, under certain names, using certain build tools, in order to be used. That's understandable: that's the way it works in most other languages. Over the last few years we consistently reminded people about the <code>goinstall</code> command -(now replaced by <a href="/cmd/go/#Download_and_install_packages_and_dependencies"><code>go get</code></a>) +(now replaced by <a href="/cmd/go/#hdr-Download_and_install_packages_and_dependencies"><code>go get</code></a>) and its conventions: first, that the import path is derived in a known way from -the URL of the source code; second, that that the place to store the sources in +the URL of the source code; second, that the place to store the sources in the local file system is derived in a known way from the import path; third, that each directory in a source tree corresponds to a single package; and fourth, that the package is built using only information in the source code. diff --git a/doc/articles/godoc_documenting_go_code.html b/doc/articles/godoc_documenting_go_code.html index ca66076ad..18a3ee953 100644 --- a/doc/articles/godoc_documenting_go_code.html +++ b/doc/articles/godoc_documenting_go_code.html @@ -65,8 +65,8 @@ package's brief description: {{code "/src/pkg/sort/sort.go" `/Package sort provides/` `/package sort/`}} <p> -They can also be detailed like the <a href="/pkg/encoding/gob/">gob package</a>'s -overview. That package uses another convention for packages +They can also be detailed like the <a href="/pkg/encoding/gob/"><code>gob</code></a> +package's overview. That package uses another convention for packages that need large amounts of introductory documentation: the package comment is placed in its own file, <a href="/src/pkg/encoding/gob/doc.go">doc.go</a>, which contains only those comments and a package clause. @@ -80,10 +80,10 @@ sentence will appear in godoc's <a href="/pkg/">package list</a>. <p> Comments that are not adjacent to a top-level declaration are omitted from godoc's output, with one notable exception. Top-level comments that begin with -the word <code>"BUG(who)”</code> are recognized as known bugs, and included in -the "Bugs” section of the package documentation. The "who” part should be the +the word <code>"BUG(who)"</code> are recognized as known bugs, and included in +the "Bugs" section of the package documentation. The "who" part should be the user name of someone who could provide more information. For example, this is a -known issue from the <a href="/pkg/bytes/#bugs">bytes package</a>: +known issue from the <a href="/pkg/bytes/#pkg-bugs"><code>bytes</code></a> package: </p> <pre> @@ -93,7 +93,7 @@ known issue from the <a href="/pkg/bytes/#bugs">bytes package</a>: <p> Godoc treats executable commands somewhat differently. Instead of inspecting the command source code, it looks for a Go source file belonging to the special -package "documentation”. The comment on the "package documentation” clause is +package "documentation". The comment on the "package documentation" clause is used as the command's documentation. For example, see the <a href="/cmd/godoc/">godoc documentation</a> and its corresponding <a href="/src/cmd/godoc/doc.go">doc.go</a> file. @@ -137,3 +137,9 @@ indexing via the <code>-path</code> flag or just by running <code>"godoc ."</cod in the source directory. See the <a href="/cmd/godoc/">godoc documentation</a> for more details. </p> + +<p> +Godoc recognizes example functions written according to the +<a href="/pkg/testing/#pkg-overview"><code>testing</code></a> package's naming +conventions and presents them appropriately. +</p> diff --git a/doc/articles/image_package.html b/doc/articles/image_package.html index a9d2f3581..ebe92a1ca 100644 --- a/doc/articles/image_package.html +++ b/doc/articles/image_package.html @@ -45,7 +45,7 @@ classic algebra: dstr, dstg, dstb, dsta := dst.RGBA() srcr, srcg, srcb, srca := src.RGBA() _, _, _, m := mask.RGBA() -const M = 1<<16 - 1 +const M = 1<<16 - 1 // The resultant red value is a blend of dstr and srcr, and ranges in [0, M]. // The calculation for green, blue and alpha is similar. dstr = (dstr*(M-m) + srcr*m) / M @@ -130,7 +130,7 @@ much easier to type. A <code>Rectangle</code> is inclusive at the top-left and exclusive at the bottom-right. For a <code>Point p</code> and a <code>Rectangle r</code>, <code>p.In(r)</code> if and only if -<code>r.Min.X <= p.X && p.X < r.Max.X</code>, and similarly for <code>Y</code>. This is analagous to how +<code>r.Min.X <= p.X && p.X < r.Max.X</code>, and similarly for <code>Y</code>. This is analagous to how a slice <code>s[i0:i1]</code> is inclusive at the low end and exclusive at the high end. (Unlike arrays and slices, a <code>Rectangle</code> often has a non-zero origin.) @@ -193,8 +193,8 @@ way to iterate over an <code>Image</code> m's pixels looks like: <pre> b := m.Bounds() -for y := b.Min.Y; y < b.Max.Y; y++ { - for x := b.Min.X; y < b.Max.X; x++ { +for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { doStuffWith(m.At(x, y)) } } diff --git a/doc/articles/json_and_go.html b/doc/articles/json_and_go.html index af7776c0a..8c4ef33a4 100644 --- a/doc/articles/json_and_go.html +++ b/doc/articles/json_and_go.html @@ -43,7 +43,7 @@ and an instance of <code>Message</code> {{code "/doc/progs/json1.go" `/m :=/`}} <p> -we can marshal a JSON-encoded version of m using <code>json.Marshal</code>: +we can marshal a JSON-encoded version of <code>m</code> using <code>json.Marshal</code>: </p> {{code "/doc/progs/json1.go" `/b, err :=/`}} @@ -82,8 +82,8 @@ is <code>nil</code>). <p> The json package only accesses the exported fields of struct types (those that -begin with an uppercase letter). Therefore only the the exported fields of a -struct will be present in the JSON output. +begin with an uppercase letter). Therefore only the exported fields of a struct +will be present in the JSON output. </p> <p> @@ -130,7 +130,7 @@ preference): <ul> <li> -An exported field with a tag of <code>"Foo"</code> (see the +An exported field with a tag of <code>`json:"Foo"`</code> (see the <a href="/ref/spec#Struct_types">Go spec</a> for more on struct tags), </li> <li> @@ -151,11 +151,11 @@ type? <p> <code>Unmarshal</code> will decode only the fields that it can find in the -destination type. In this case, only the Name field of m will be populated, -and the Food field will be ignored. This behavior is particularly useful when -you wish to pick only a few specific fields out of a large JSON blob. It also -means that any unexported fields in the destination struct will be unaffected -by <code>Unmarshal</code>. +destination type. In this case, only the <code>Name</code> field of m will be +populated, and the <code>Food</code> field will be ignored. This behavior is +particularly useful when you wish to pick only a few specific fields out of a +large JSON blob. It also means that any unexported fields in the destination +struct will be unaffected by <code>Unmarshal</code>. </p> <p> @@ -163,7 +163,7 @@ But what if you don't know the structure of your JSON data beforehand? </p> <p> -<b>Generic JSON with interface{}</b> +<b>Generic JSON with <code>interface{}</code></b> </p> <p> @@ -190,11 +190,12 @@ Or, if the underlying type is unknown, a type switch determines the type: {{code "/doc/progs/json2.go" `/switch v/` `/STOP/`}} - +<p> The json package uses <code>map[string]interface{}</code> and <code>[]interface{}</code> values to store arbitrary JSON objects and arrays; it will happily unmarshal any valid JSON blob into a plain <code>interface{}</code> value. The default concrete Go types are: +</p> <ul> <li> diff --git a/doc/articles/json_rpc_tale_of_interfaces.html b/doc/articles/json_rpc_tale_of_interfaces.html index a545f55f6..0db366f33 100644 --- a/doc/articles/json_rpc_tale_of_interfaces.html +++ b/doc/articles/json_rpc_tale_of_interfaces.html @@ -57,7 +57,7 @@ original functionality. From there it is simple to build a After some similar changes to the client side, this was the full extent of the work we needed to do on the RPC package. This whole exercise took about 20 minutes! After tidying up and testing the new code, the -<a href="http://code.google.com/p/go/source/diff?spec=svn9daf796ebf1cae97b2fcf760a4ab682f1f063f29&r=9daf796ebf1cae97b2fcf760a4ab682f1f063f29&format=side&path=/src/pkg/rpc/server.go">final changeset</a> +<a href="http://code.google.com/p/go/source/diff?spec=svn9daf796ebf1cae97b2fcf760a4ab682f1f063f29&r=9daf796ebf1cae97b2fcf760a4ab682f1f063f29&format=side&path=/src/pkg/rpc/server.go">final changeset</a> was submitted. </p> diff --git a/doc/articles/laws_of_reflection.html b/doc/articles/laws_of_reflection.html index 826a054f2..81f6697ce 100644 --- a/doc/articles/laws_of_reflection.html +++ b/doc/articles/laws_of_reflection.html @@ -213,7 +213,7 @@ type: float64 You might be wondering where the interface is here, since the program looks like it's passing the <code>float64</code> variable <code>x</code>, not an interface value, to <code>reflect.TypeOf</code>. But it's there; as -<a href="/pkg/reflect/#Type.TypeOf">godoc reports</a>, the signature of +<a href="/pkg/reflect/#TypeOf">godoc reports</a>, the signature of <code>reflect.TypeOf</code> includes an empty interface: </p> diff --git a/doc/articles/race_detector.html b/doc/articles/race_detector.html new file mode 100644 index 000000000..400d96b19 --- /dev/null +++ b/doc/articles/race_detector.html @@ -0,0 +1,369 @@ +<!--{ + "Title": "Data Race Detector", + "Template": true +}--> + +<h2 id="Introduction">Introduction</h2> + +<p> +Data races are one of the most common and hardest to debug types of bugs in concurrent systems. A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write. See the <a href="/ref/mem/">The Go Memory Model</a> for details. +</p> + +<p> +Here is an example of a data race that can lead to crashes and memory corruption: +</p> + +<pre> +func main() { + c := make(chan bool) + m := make(map[string]string) + go func() { + m["1"] = "a" // First conflicting access. + c <- true + }() + m["2"] = "b" // Second conflicting access. + <-c + for k, v := range m { + fmt.Println(k, v) + } +} +</pre> + +<h2 id="Usage">Usage</h2> + +<p> +Fortunately, Go includes a built-in data race detector. To use it, add the <code>-race</code> flag to the go command: +</p> + +<pre> +$ go test -race mypkg // to test the package +$ go run -race mysrc.go // to run the source file +$ go build -race mycmd // to build the command +$ go install -race mypkg // to install the package +</pre> + +<h2 id="Report_Format">Report Format</h2> + +<p> +When the race detector finds a data race in the program, it prints a report. The report contains stack traces for conflicting accesses, as well as stacks where the involved goroutines were created. For example: +</p> + +<pre> +WARNING: DATA RACE +Read by goroutine 185: + net.(*pollServer).AddFD() + src/pkg/net/fd_unix.go:89 +0x398 + net.(*pollServer).WaitWrite() + src/pkg/net/fd_unix.go:247 +0x45 + net.(*netFD).Write() + src/pkg/net/fd_unix.go:540 +0x4d4 + net.(*conn).Write() + src/pkg/net/net.go:129 +0x101 + net.func·060() + src/pkg/net/timeout_test.go:603 +0xaf + +Previous write by goroutine 184: + net.setWriteDeadline() + src/pkg/net/sockopt_posix.go:135 +0xdf + net.setDeadline() + src/pkg/net/sockopt_posix.go:144 +0x9c + net.(*conn).SetDeadline() + src/pkg/net/net.go:161 +0xe3 + net.func·061() + src/pkg/net/timeout_test.go:616 +0x3ed + +Goroutine 185 (running) created at: + net.func·061() + src/pkg/net/timeout_test.go:609 +0x288 + +Goroutine 184 (running) created at: + net.TestProlongTimeout() + src/pkg/net/timeout_test.go:618 +0x298 + testing.tRunner() + src/pkg/testing/testing.go:301 +0xe8 +</pre> + +<h2 id="Options">Options</h2> + +<p> +The <code>GORACE</code> environment variable sets race detector options. The format is: +</p> + +<pre> +GORACE="option1=val1 option2=val2" +</pre> + +<p> +The options are: +</p> + +<ul> +<li> +<code>log_path</code> (default <code>stderr</code>): The race detector writes +its report to a file named log_path.pid. The special names <code>stdout</code> +and <code>stderr</code> cause reports to be written to standard output and +standard error, respectively. +</li> + +<li> +<code>exitcode</code> (default <code>66</code>): The exit status to use when +exiting after a detected race. +</li> + +<li> +<code>strip_path_prefix</code> (default <code>""</code>): Strip this prefix +from all reported file paths, to make reports more concise. +</li> + +<li> +<code>history_size</code> (default <code>1</code>): The per-goroutine memory +access history is <code>32K * 2**history_size elements</code>. Increasing this +value can avoid a "failed to restore the stack" error in reports, but at the +cost of increased memory usage. +</li> +</ul> + +<p> +Example: +</p> + +<pre> +$ GORACE="log_path=/tmp/race/report strip_path_prefix=/my/go/sources/" go test -race +</pre> + +<h2 id="Excluding_Tests">Excluding Tests</h2> + +<p> +When you build with <code>-race</code> flag, go command defines additional +<a href="/pkg/go/build/#Build_Constraints">build tag</a> <code>race</code>. +You can use it to exclude some code/tests under the race detector. For example: +</p> + +<pre> +// +build !race + +package foo + +// The test contains a data race. See issue 123. +func TestFoo(t *testing.T) { + // ... +} + +// The test fails under the race detector due to timeouts. +func TestBar(t *testing.T) { + // ... +} + +// The test takes too long under the race detector. +func TestBaz(t *testing.T) { + // ... +} +</pre> + +<h2 id="How_To_Use">How To Use</h2> + +<p> +To start, run your tests using the race detector (<code>go test -race</code>). +The race detector only finds races that happen at runtime, so it can't find +races in code paths that are not executed. If your tests have incomplete coverage, +you may find more races by running a binary built with <code>-race</code> under a realistic +workload. +</p> + +<h2 id="Typical_Data_Races">Typical Data Races</h2> + +<p> +Here are some typical data races. All of them can be detected with the race detector. +</p> + +<h3 id="Race_on_loop_counter">Race on loop counter</h3> + +<pre> +func main() { + var wg sync.WaitGroup + wg.Add(5) + for i := 0; i < 5; i++ { + go func() { + fmt.Println(i) // Not the 'i' you are looking for. + wg.Done() + }() + } + wg.Wait() +} +</pre> + +<p> +The variable <code>i</code> in the function literal is the same variable used by the loop, so +the read in the goroutine races with the loop increment. (This program typically +prints 55555, not 01234.) The program can be fixed by making a copy of the +variable: +</p> + +<pre> +func main() { + var wg sync.WaitGroup + wg.Add(5) + for i := 0; i < 5; i++ { + go func(j int) { + fmt.Println(j) // Good. Read local copy of the loop counter. + wg.Done() + }(i) + } + wg.Wait() +} +</pre> + +<h3 id="Accidentally_shared_variable">Accidentally shared variable</h3> + +<pre> +// ParallelWrite writes data to file1 and file2, returns the errors. +func ParallelWrite(data []byte) chan error { + res := make(chan error, 2) + f1, err := os.Create("file1") + if err != nil { + res <- err + } else { + go func() { + // This err is shared with the main goroutine, + // so the write races with the write below. + _, err = f1.Write(data) + res <- err + f1.Close() + }() + } + f2, err := os.Create("file2") // The second conflicting write to err. + if err != nil { + res <- err + } else { + go func() { + _, err = f2.Write(data) + res <- err + f2.Close() + }() + } + return res +} +</pre> + +<p> +The fix is to introduce new variables in the goroutines (note <code>:=</code>): +</p> + +<pre> + ... + _, err := f1.Write(data) + ... + _, err := f2.Write(data) + ... +</pre> + +<h3 id="Unprotected_global_variable">Unprotected global variable</h3> + +<p> +If the following code is called from several goroutines, it leads to bad races on the <code>service</code> map. +Concurrent reads and writes of a map are not safe: +</p> + +<pre> +var service map[string]net.Addr + +func RegisterService(name string, addr net.Addr) { + service[name] = addr +} + +func LookupService(name string) net.Addr { + return service[name] +} +</pre> + +<p> +To make the code safe, protect the accesses with a mutex: +</p> + +<pre> +var ( + service map[string]net.Addr + serviceMu sync.Mutex +) + +func RegisterService(name string, addr net.Addr) { + serviceMu.Lock() + defer serviceMu.Unlock() + service[name] = addr +} + +func LookupService(name string) net.Addr { + serviceMu.Lock() + defer serviceMu.Unlock() + return service[name] +} +</pre> + +<h3 id="Primitive_unprotected_variable">Primitive unprotected variable</h3> + +<p> +Data races can happen on variables of primitive types as well (<code>bool</code>, <code>int</code>, <code>int64</code>, etc.), like in the following example: +</p> + +<pre> +type Watchdog struct{ last int64 } + +func (w *Watchdog) KeepAlive() { + w.last = time.Now().UnixNano() // First conflicting access. +} + +func (w *Watchdog) Start() { + go func() { + for { + time.Sleep(time.Second) + // Second conflicting access. + if w.last < time.Now().Add(-10*time.Second).UnixNano() { + fmt.Println("No keepalives for 10 seconds. Dying.") + os.Exit(1) + } + } + }() +} +</pre> + +<p> +Even such “innocent” data races can lead to hard to debug problems caused by (1) non-atomicity of the memory accesses, (2) interference with compiler optimizations and (3) processor memory access reordering issues. +</p> + +<p> +A typical fix for this race is to use a channel or a mutex. +To preserve the lock-free behavior, one can also use the <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package. +</p> + +<pre> +type Watchdog struct{ last int64 } + +func (w *Watchdog) KeepAlive() { + atomic.StoreInt64(&w.last, time.Now().UnixNano()) +} + +func (w *Watchdog) Start() { + go func() { + for { + time.Sleep(time.Second) + if atomic.LoadInt64(&w.last) < time.Now().Add(-10*time.Second).UnixNano() { + fmt.Println("No keepalives for 10 seconds. Dying.") + os.Exit(1) + } + } + }() +} +</pre> + +<h2 id="Supported_Systems">Supported Systems</h2> + +<p> +The race detector runs on <code>darwin/amd64</code>, <code>linux/amd64</code>, and <code>windows/amd64</code>. +</p> + +<h2 id="Runtime_Overheads">Runtime Overhead</h2> + +<p> +The cost of race detection varies by program, but for a typical program, memory +usage may increase by 5-10x and execution time by 2-20x. +</p> diff --git a/doc/articles/slices_usage_and_internals.html b/doc/articles/slices_usage_and_internals.html index 810b0a41f..7eb751b45 100644 --- a/doc/articles/slices_usage_and_internals.html +++ b/doc/articles/slices_usage_and_internals.html @@ -243,7 +243,7 @@ slice itself) of a re-slice modifies the elements of the original slice: d := []byte{'r', 'o', 'a', 'd'} e := d[2:] // e == []byte{'a', 'd'} -e[1] == 'm' +e[1] = 'm' // e == []byte{'a', 'm'} // d == []byte{'r', 'o', 'a', 'm'} </pre> diff --git a/doc/articles/wiki/get.go b/doc/articles/wiki/get.go index c6e9bf28b..b3e464b34 100644 --- a/doc/articles/wiki/get.go +++ b/doc/articles/wiki/get.go @@ -13,11 +13,13 @@ import ( "net/http" "os" "strings" + "time" ) var ( post = flag.String("post", "", "urlencoded form data to POST") addr = flag.Bool("addr", false, "find open address and print to stdout") + wait = flag.Duration("wait_for_port", 0, "if non-zero, the amount of time to wait for the address to become available") ) func main() { @@ -37,11 +39,18 @@ func main() { } var r *http.Response var err error - if *post != "" { - b := strings.NewReader(*post) - r, err = http.Post(url, "application/x-www-form-urlencoded", b) - } else { - r, err = http.Get(url) + loopUntil := time.Now().Add(*wait) + for { + if *post != "" { + b := strings.NewReader(*post) + r, err = http.Post(url, "application/x-www-form-urlencoded", b) + } else { + r, err = http.Get(url) + } + if err == nil || *wait == 0 || time.Now().After(loopUntil) { + break + } + time.Sleep(100 * time.Millisecond) } if err != nil { log.Fatal(err) diff --git a/doc/articles/wiki/index.html b/doc/articles/wiki/index.html index 6c45d7178..ea3507f4d 100644 --- a/doc/articles/wiki/index.html +++ b/doc/articles/wiki/index.html @@ -46,7 +46,7 @@ $ cd gowiki </pre> <p> -Create a file named <code>wiki.go</code>, open it in your favorite editor, and +Create a file named <code>wiki.go</code>, open it in your favorite editor, and add the following lines: </p> @@ -60,8 +60,8 @@ import ( </pre> <p> -We import the <code>fmt</code> and <code>ioutil</code> packages from the Go -standard library. Later, as we implement additional functionality, we will +We import the <code>fmt</code> and <code>ioutil</code> packages from the Go +standard library. Later, as we implement additional functionality, we will add more packages to this <code>import</code> declaration. </p> @@ -77,7 +77,7 @@ the title and body. {{code "doc/articles/wiki/part1.go" `/^type Page/` `/}/`}} <p> -The type <code>[]byte</code> means "a <code>byte</code> slice". +The type <code>[]byte</code> means "a <code>byte</code> slice". (See <a href="/doc/articles/slices_usage_and_internals.html">Slices: usage and internals</a> for more on slices.) The <code>Body</code> element is a <code>[]byte</code> rather than @@ -86,8 +86,8 @@ libraries we will use, as you'll see below. </p> <p> -The <code>Page</code> struct describes how page data will be stored in memory. -But what about persistent storage? We can address that by creating a +The <code>Page</code> struct describes how page data will be stored in memory. +But what about persistent storage? We can address that by creating a <code>save</code> method on <code>Page</code>: </p> @@ -96,11 +96,11 @@ But what about persistent storage? We can address that by creating a <p> This method's signature reads: "This is a method named <code>save</code> that takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes -no parameters, and returns a value of type <code>error</code>." +no parameters, and returns a value of type <code>error</code>." </p> <p> -This method will save the <code>Page</code>'s <code>Body</code> to a text +This method will save the <code>Page</code>'s <code>Body</code> to a text file. For simplicity, we will use the <code>Title</code> as the file name. </p> @@ -110,35 +110,37 @@ that is the return type of <code>WriteFile</code> (a standard library function that writes a byte slice to a file). The <code>save</code> method returns the error value, to let the application handle it should anything go wrong while writing the file. If all goes well, <code>Page.save()</code> will return -<code>nil</code> (the zero-value for pointers, interfaces, and some other +<code>nil</code> (the zero-value for pointers, interfaces, and some other types). </p> <p> -The octal integer constant <code>0600</code>, passed as the third parameter to +The octal integer literal <code>0600</code>, passed as the third parameter to <code>WriteFile</code>, indicates that the file should be created with read-write permissions for the current user only. (See the Unix man page <code>open(2)</code> for details.) </p> <p> -We will want to load pages, too: +In addition to saving pages, we will want to load pages, too: </p> {{code "doc/articles/wiki/part1-noerror.go" `/^func loadPage/` `/^}/`}} <p> The function <code>loadPage</code> constructs the file name from -<code>Title</code>, reads the file's contents into a new -<code>Page</code>, and returns a pointer to that new <code>page</code>. +the title parameter, reads the file's contents into a new +variable <code>body</code>, and returns two values: a pointer to a +<code>Page</code> literal constructed with the proper title and body +values and <code>nil</code> for the error value. </p> <p> -Functions can return multiple values. The standard library function -<code>io.ReadFile</code> returns <code>[]byte</code> and <code>error</code>. +Functions can return multiple values. The standard library function +<code>io.ReadFile</code> returns <code>[]byte</code> and <code>error</code>. In <code>loadPage</code>, error isn't being handled yet; the "blank identifier" represented by the underscore (<code>_</code>) symbol is used to throw away the -error return value (in essence, assigning the value to nothing). +error return value (in essence, assigning the value to nothing). </p> <p> @@ -152,7 +154,7 @@ function to return <code>*Page</code> and <code>error</code>. <p> Callers of this function can now check the second parameter; if it is <code>nil</code> then it has successfully loaded a Page. If not, it will be an -<code>error</code> that can be handled by the caller (see the +<code>error</code> that can be handled by the caller (see the <a href="/ref/spec#Errors">language specification</a> for details). </p> @@ -172,7 +174,7 @@ printed to the screen. </p> <p> -You can compile and run the program like this: +You can compile and run the program like this: </p> <pre> @@ -182,7 +184,7 @@ This is a sample page. </pre> <p> -(If you're using Windows you must type "<code>wiki</code>" without the +(If you're using Windows you must type "<code>wiki</code>" without the "<code>./</code>" to run the program.) </p> @@ -199,10 +201,10 @@ Here's a full working example of a simple web server: {{code "doc/articles/wiki/http-sample.go"}} <p> -The <code>main</code> function begins with a call to -<code>http.HandleFunc</code>, which tells the <code>http</code> package to -handle all requests to the web root (<code>"/"</code>) with -<code>handler</code>. +The <code>main</code> function begins with a call to +<code>http.HandleFunc</code>, which tells the <code>http</code> package to +handle all requests to the web root (<code>"/"</code>) with +<code>handler</code>. </p> <p> @@ -219,20 +221,20 @@ its arguments. </p> <p> -An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing +An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing to it, we send data to the HTTP client. </p> <p> An <code>http.Request</code> is a data structure that represents the client -HTTP request. The string <code>r.URL.Path</code> is the path component -of the request URL. The trailing <code>[1:]</code> means -"create a sub-slice of <code>Path</code> from the 1st character to the end." +HTTP request. <code>r.URL.Path</code> is the path component +of the request URL. The trailing <code>[1:]</code> means +"create a sub-slice of <code>Path</code> from the 1st character to the end." This drops the leading "/" from the path name. </p> <p> -If you run this program and access the URL: +If you run this program and access the URL: </p> <pre>http://localhost:8080/monkeys</pre> <p> @@ -249,13 +251,14 @@ To use the <code>net/http</code> package, it must be imported: <pre> import ( "fmt" - <b>"net/http"</b> "io/ioutil" + <b>"net/http"</b> ) </pre> <p> -Let's create a handler to view a wiki page: +Let's create a handler, <code>viewHandler</code> that will allow users to +view a wiki page. It will handle URLs prefixed with "/view/". </p> {{code "doc/articles/wiki/part2.go" `/^const lenPath/`}} @@ -264,28 +267,28 @@ Let's create a handler to view a wiki page: <p> First, this function extracts the page title from <code>r.URL.Path</code>, -the path component of the request URL. The global constant +the path component of the request URL. The global constant <code>lenPath</code> is the length of the leading <code>"/view/"</code> component of the request path. -The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the -first 6 characters of the string. This is because the path will invariably -begin with <code>"/view/"</code>, which is not part of the page title. +The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the +first 6 characters of the string. This is because the path will invariably +begin with <code>"/view/"</code>, which is not part of the page's title. </p> <p> -The function then loads the page data, formats the page with a string of simple -HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>. +The function then loads the page data, formats the page with a string of simple +HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>. </p> <p> -Again, note the use of <code>_</code> to ignore the <code>error</code> +Again, note the use of <code>_</code> to ignore the <code>error</code> return value from <code>loadPage</code>. This is done here for simplicity and generally considered bad practice. We will attend to this later. </p> <p> -To use this handler, we create a <code>main</code> function that -initializes <code>http</code> using the <code>viewHandler</code> to handle +To use this handler, we rewrite our <code>main</code> function to +initialize <code>http</code> using the <code>viewHandler</code> to handle any requests under the path <code>/view/</code>. </p> @@ -311,6 +314,11 @@ $ ./wiki </pre> <p> +(If you're using Windows you must type "<code>wiki</code>" without the +"<code>./</code>" to run the program.) +</p> + +<p> With this web server running, a visit to <code><a href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code> should show a page titled "test" containing the words "Hello world". @@ -326,14 +334,14 @@ form. </p> <p> -First, we add them to <code>main()</code>: +First, we add them to <code>main()</code>: </p> {{code "doc/articles/wiki/final-noclosure.go" `/^func main/` `/^}/`}} <p> -The function <code>editHandler</code> loads the page -(or, if it doesn't exist, create an empty <code>Page</code> struct), +The function <code>editHandler</code> loads the page +(or, if it doesn't exist, create an empty <code>Page</code> struct), and displays an HTML form. </p> @@ -343,7 +351,7 @@ and displays an HTML form. This function will work fine, but all that hard-coded HTML is ugly. Of course, there is a better way. </p> - + <h2>The <code>html/template</code> package</h2> <p> @@ -354,20 +362,20 @@ underlying Go code. </p> <p> -First, we must add <code>html/template</code> to the list of imports: +First, we must add <code>html/template</code> to the list of imports. We +also won't be using <code>fmt</code> anymore, so we have to remove that. </p> <pre> import ( <b>"html/template"</b> - "http" "io/ioutil" - "os" + "net/http" ) </pre> <p> -Let's create a template file containing the HTML form. +Let's create a template file containing the HTML form. Open a new file named <code>edit.html</code>, and add the following lines: </p> @@ -381,8 +389,8 @@ HTML: {{code "doc/articles/wiki/final-noerror.go" `/^func editHandler/` `/^}/`}} <p> -The function <code>template.ParseFiles</code> will read the contents of -<code>edit.html</code> and return a <code>*template.Template</code>. +The function <code>template.ParseFiles</code> will read the contents of +<code>edit.html</code> and return a <code>*template.Template</code>. </p> <p> @@ -405,12 +413,7 @@ HTML. </p> <p> -Now that we've removed the <code>fmt.Fprintf</code> statement, we can remove -<code>"fmt"</code> from the <code>import</code> list. -</p> - -<p> -While we're working with templates, let's create a template for our +Since we're working with templates now, let's create a template for our <code>viewHandler</code> called <code>view.html</code>: </p> @@ -428,28 +431,31 @@ handlers. Let's remove this duplication by moving the templating code to its own function: </p> +{{code "doc/articles/wiki/final-template.go" `/^func renderTemplate/` `/^}/`}} {{code "doc/articles/wiki/final-template.go" `/^func viewHandler/` `/^}/`}} {{code "doc/articles/wiki/final-template.go" `/^func editHandler/` `/^}/`}} -{{code "doc/articles/wiki/final-template.go" `/^func renderTemplate/` `/^}/`}} <p> -The handlers are now shorter and simpler. +If we comment out the registration of our unimplemented save handler in +<code>main</code>, we can once again build and test our program. +<a href="part3.go">Click here to view the code we've written so far.</a> </p> <h2>Handling non-existent pages</h2> <p> What if you visit <a href="http://localhost:8080/view/APageThatDoesntExist"> -<code>/view/APageThatDoesntExist</code></a>? The program will crash. This is -because it ignores the error return value from <code>loadPage</code>. Instead, -if the requested Page doesn't exist, it should redirect the client to the edit -Page so the content may be created: +<code>/view/APageThatDoesntExist</code></a>? You'll see a page containing +HTML. This is because it ignores the error return value from +<code>loadPage</code> and continues to try and fill out the template +with no data. Instead, if the requested Page doesn't exist, it should +redirect the client to the edit Page so the content may be created: </p> -{{code "doc/articles/wiki/final-noclosure.go" `/^func viewHandler/` `/^}/`}} +{{code "doc/articles/wiki/part3-errorhandling.go" `/^func viewHandler/` `/^}/`}} <p> -The <code>http.Redirect</code> function adds an HTTP status code of +The <code>http.Redirect</code> function adds an HTTP status code of <code>http.StatusFound</code> (302) and a <code>Location</code> header to the HTTP response. </p> @@ -457,22 +463,24 @@ header to the HTTP response. <h2>Saving Pages</h2> <p> -The function <code>saveHandler</code> will handle the form submission. +The function <code>saveHandler</code> will handle the submission of forms +located on the edit pages. After uncommenting the related line in +<code>main</code>, let's implement the the handler: </p> {{code "doc/articles/wiki/final-template.go" `/^func saveHandler/` `/^}/`}} <p> -The page title (provided in the URL) and the form's only field, -<code>Body</code>, are stored in a new <code>Page</code>. +The page title (provided in the URL) and the form's only field, +<code>Body</code>, are stored in a new <code>Page</code>. The <code>save()</code> method is then called to write the data to a file, and the client is redirected to the <code>/view/</code> page. </p> <p> The value returned by <code>FormValue</code> is of type <code>string</code>. -We must convert that value to <code>[]byte</code> before it will fit into -the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform +We must convert that value to <code>[]byte</code> before it will fit into +the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform the conversion. </p> @@ -481,9 +489,9 @@ the conversion. <p> There are several places in our program where errors are being ignored. This is bad practice, not least because when an error does occur the program will -crash. A better solution is to handle the errors and return an error message -to the user. That way if something does go wrong, the server will continue to -function and the user will be notified. +have unintended behavior. A better solution is to handle the errors and return +an error message to the user. That way if something does go wrong, the server +will function exactly how we want and the user can be notified. </p> <p> @@ -493,7 +501,7 @@ First, let's handle the errors in <code>renderTemplate</code>: {{code "doc/articles/wiki/final-parsetemplate.go" `/^func renderTemplate/` `/^}/`}} <p> -The <code>http.Error</code> function sends a specified HTTP response code +The <code>http.Error</code> function sends a specified HTTP response code (in this case "Internal Server Error") and error message. Already the decision to put this in a separate function is paying off. </p> @@ -502,18 +510,18 @@ Already the decision to put this in a separate function is paying off. Now let's fix up <code>saveHandler</code>: </p> -{{code "doc/articles/wiki/final-noclosure.go" `/^func saveHandler/` `/^}/`}} +{{code "doc/articles/wiki/part3-errorhandling.go" `/^func saveHandler/` `/^}/`}} <p> -Any errors that occur during <code>p.save()</code> will be reported +Any errors that occur during <code>p.save()</code> will be reported to the user. </p> <h2>Template caching</h2> <p> -There is an inefficiency in this code: <code>renderTemplate</code> calls -<code>ParseFiles</code> every time a page is rendered. +There is an inefficiency in this code: <code>renderTemplate</code> calls +<code>ParseFiles</code> every time a page is rendered. A better approach would be to call <code>ParseFiles</code> once at program initialization, parsing all templates into a single <code>*Template</code>. Then we can use the @@ -536,10 +544,11 @@ can't be loaded the only sensible thing to do is exit the program. </p> <p> -A <code>for</code> loop is used with a <code>range</code> statement to iterate -over an array constant containing the names of the templates we want parsed. -If we were to add more templates to our program, we would add their names to -that array. +The <code>ParseFiles</code> function takes any number of string arguments that +identify our template files, and parses those files into templates that are +named after the base file name. If we were to add more templates to our +program, we would add their names to the <code>ParseFiles</code> call's +arguments. </p> <p> @@ -571,25 +580,27 @@ Then we can create a global variable to store our validation regexp: {{code "doc/articles/wiki/final-noclosure.go" `/^var titleValidator/`}} <p> -The function <code>regexp.MustCompile</code> will parse and compile the -regular expression, and return a <code>regexp.Regexp</code>. +The function <code>regexp.MustCompile</code> will parse and compile the +regular expression, and return a <code>regexp.Regexp</code>. <code>MustCompile</code> is distinct from <code>Compile</code> in that it will panic if the expression compilation fails, while <code>Compile</code> returns -an <code>error</code> as a second parameter. +an <code>error</code> as a second parameter. </p> <p> -Now, let's write a function that extracts the title string from the request -URL, and tests it against our <code>TitleValidator</code> expression: +Now, let's write a function, <code>getTitle</code>, that extracts the title +string from the request URL, and tests it against our +<code>TitleValidator</code> expression: </p> {{code "doc/articles/wiki/final-noclosure.go" `/func getTitle/` `/^}/`}} <p> If the title is valid, it will be returned along with a <code>nil</code> -error value. If the title is invalid, the function will write a -"404 Not Found" error to the HTTP connection, and return an error to the -handler. +error value. If the title is invalid, the function will write a +"404 Not Found" error to the HTTP connection, and return an error to the +handler. To create a new error, we have to import the <code>errors</code> +package. </p> <p> @@ -604,10 +615,10 @@ Let's put a call to <code>getTitle</code> in each of the handlers: <p> Catching the error condition in each handler introduces a lot of repeated code. -What if we could wrap each of the handlers in a function that does this -validation and error checking? Go's -<a href="/ref/spec#Function_declarations">function -literals</a> provide a powerful means of abstracting functionality +What if we could wrap each of the handlers in a function that does this +validation and error checking? Go's +<a href="/ref/spec#Function_declarations">function +literals</a> provide a powerful means of abstracting functionality that can help us here. </p> @@ -654,19 +665,19 @@ Now we can take the code from <code>getTitle</code> and use it here <p> The closure returned by <code>makeHandler</code> is a function that takes an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other -words, an <code>http.HandlerFunc</code>). +words, an <code>http.HandlerFunc</code>). The closure extracts the <code>title</code> from the request path, and validates it with the <code>TitleValidator</code> regexp. If the <code>title</code> is invalid, an error will be written to the -<code>ResponseWriter</code> using the <code>http.NotFound</code> function. +<code>ResponseWriter</code> using the <code>http.NotFound</code> function. If the <code>title</code> is valid, the enclosed handler function <code>fn</code> will be called with the <code>ResponseWriter</code>, <code>Request</code>, and <code>title</code> as arguments. </p> <p> -Now we can wrap the handler functions with <code>makeHandler</code> in -<code>main</code>, before they are registered with the <code>http</code> +Now we can wrap the handler functions with <code>makeHandler</code> in +<code>main</code>, before they are registered with the <code>http</code> package: </p> @@ -698,7 +709,7 @@ $ ./wiki <p> Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a> -should present you with the page edit form. You should then be able to +should present you with the page edit form. You should then be able to enter some text, click 'Save', and be redirected to the newly created page. </p> @@ -710,11 +721,11 @@ Here are some simple tasks you might want to tackle on your own: <ul> <li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>. -<li>Add a handler to make the web root redirect to +<li>Add a handler to make the web root redirect to <code>/view/FrontPage</code>.</li> <li>Spruce up the page templates by making them valid HTML and adding some CSS rules.</li> -<li>Implement inter-page linking by converting instances of +<li>Implement inter-page linking by converting instances of <code>[PageName]</code> to <br> <code><a href="/view/PageName">PageName</a></code>. (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this) diff --git a/doc/articles/wiki/part3-errorhandling.go b/doc/articles/wiki/part3-errorhandling.go new file mode 100644 index 000000000..945aa1e39 --- /dev/null +++ b/doc/articles/wiki/part3-errorhandling.go @@ -0,0 +1,75 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "html/template" + "io/ioutil" + "net/http" +) + +type Page struct { + Title string + Body []byte +} + +func (p *Page) save() error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) +} + +func loadPage(title string) (*Page, error) { + filename := title + ".txt" + body, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return &Page{Title: title, Body: body}, nil +} + +const lenPath = len("/view/") + +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { + t, _ := template.ParseFiles(tmpl + ".html") + t.Execute(w, p) +} + +func viewHandler(w http.ResponseWriter, r *http.Request) { + title := r.URL.Path[lenPath:] + p, err := loadPage(title) + if err != nil { + http.Redirect(w, r, "/edit/"+title, http.StatusFound) + return + } + renderTemplate(w, "view", p) +} + +func editHandler(w http.ResponseWriter, r *http.Request) { + title := r.URL.Path[lenPath:] + p, err := loadPage(title) + if err != nil { + p = &Page{Title: title} + } + renderTemplate(w, "edit", p) +} + +func saveHandler(w http.ResponseWriter, r *http.Request) { + title := r.URL.Path[lenPath:] + body := r.FormValue("body") + p := &Page{Title: title, Body: []byte(body)} + err := p.save() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + http.Redirect(w, r, "/view/"+title, http.StatusFound) +} + +func main() { + http.HandleFunc("/view/", viewHandler) + http.HandleFunc("/edit/", editHandler) + http.HandleFunc("/save/", saveHandler) + http.ListenAndServe(":8080", nil) +} diff --git a/doc/articles/wiki/part3.go b/doc/articles/wiki/part3.go new file mode 100644 index 000000000..7fe4351af --- /dev/null +++ b/doc/articles/wiki/part3.go @@ -0,0 +1,59 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "html/template" + "io/ioutil" + "net/http" +) + +type Page struct { + Title string + Body []byte +} + +func (p *Page) save() error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) +} + +func loadPage(title string) (*Page, error) { + filename := title + ".txt" + body, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return &Page{Title: title, Body: body}, nil +} + +const lenPath = len("/view/") + +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { + t, _ := template.ParseFiles(tmpl + ".html") + t.Execute(w, p) +} + +func viewHandler(w http.ResponseWriter, r *http.Request) { + title := r.URL.Path[lenPath:] + p, _ := loadPage(title) + renderTemplate(w, "view", p) +} + +func editHandler(w http.ResponseWriter, r *http.Request) { + title := r.URL.Path[lenPath:] + p, err := loadPage(title) + if err != nil { + p = &Page{Title: title} + } + renderTemplate(w, "edit", p) +} + +func main() { + http.HandleFunc("/view/", viewHandler) + http.HandleFunc("/edit/", editHandler) + //http.HandleFunc("/save/", saveHandler) + http.ListenAndServe(":8080", nil) +} diff --git a/doc/articles/wiki/test.bash b/doc/articles/wiki/test.bash index 5c2cb60dc..02ed1894a 100755 --- a/doc/articles/wiki/test.bash +++ b/doc/articles/wiki/test.bash @@ -18,11 +18,10 @@ go build -o final-test.bin final-test.go (./final-test.bin) & wiki_pid=$! -sleep 1 - -./get.bin http://$addr/edit/Test > test_edit.out +./get.bin --wait_for_port=5s http://$addr/edit/Test > test_edit.out diff -u test_edit.out test_edit.good -./get.bin -post=body=some%20content http://$addr/save/Test +./get.bin -post=body=some%20content http://$addr/save/Test > test_save.out +diff -u test_save.out test_view.good # should be the same as viewing diff -u Test.txt test_Test.txt.good ./get.bin http://$addr/view/Test > test_view.out diff -u test_view.out test_view.good |