Update go dependencies
This commit is contained in:
parent
432f534383
commit
f4a4daed84
1299 changed files with 71186 additions and 91183 deletions
12
vendor/google.golang.org/api/.gitignore
generated
vendored
Normal file
12
vendor/google.golang.org/api/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
_obj/
|
||||
*_testmain.go
|
||||
clientid.dat
|
||||
clientsecret.dat
|
||||
/google-api-go-generator/google-api-go-generator
|
||||
|
||||
*.6
|
||||
*.8
|
||||
*~
|
||||
*.out
|
||||
*.test
|
||||
*.exe
|
||||
1
vendor/google.golang.org/api/.hgtags
generated
vendored
Normal file
1
vendor/google.golang.org/api/.hgtags
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
b571b553f8c057cb6952ce817dfb09b6e34a8c0b release
|
||||
10
vendor/google.golang.org/api/AUTHORS
generated
vendored
Normal file
10
vendor/google.golang.org/api/AUTHORS
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# This is the official list of authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# Please keep the list sorted.
|
||||
Google Inc.
|
||||
484
vendor/google.golang.org/api/CONTRIBUTING.md
generated
vendored
Normal file
484
vendor/google.golang.org/api/CONTRIBUTING.md
generated
vendored
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
# Contributing to the Google API Go Client
|
||||
|
||||
## Master git repo
|
||||
|
||||
Our master git repo is https://code.googlesource.com/google-api-go-client
|
||||
|
||||
## Pull Requests
|
||||
|
||||
We do **NOT** use Github pull requests. We use Gerrit instead
|
||||
with the same workflow as Go. See below.
|
||||
|
||||
## The source tree
|
||||
|
||||
Most of this project is auto-generated.
|
||||
|
||||
The notable directories which are not auto-generated:
|
||||
|
||||
```
|
||||
google-api-go-generator/ -- the generator itself
|
||||
googleapi/ -- shared common code, used by auto-generated code
|
||||
examples/ -- sample code
|
||||
```
|
||||
|
||||
# Contribution Guidelines
|
||||
|
||||
## Introduction
|
||||
|
||||
This document explains how to contribute changes to the google-api-go-client project.
|
||||
|
||||
## Testing redux
|
||||
|
||||
You've written and tested your code, but
|
||||
before sending code out for review, run all the tests for the whole
|
||||
tree to make sure the changes don't break other packages or programs:
|
||||
|
||||
```
|
||||
$ make cached
|
||||
$ go test ./...
|
||||
...
|
||||
ok google.golang.org/api/google-api-go-generator 0.226s
|
||||
ok google.golang.org/api/googleapi 0.015s
|
||||
...
|
||||
```
|
||||
|
||||
Ideally, you will add unit tests to one of the above directories to
|
||||
demonstrate the changes you are making and include the tests with your
|
||||
code review.
|
||||
|
||||
## Code review
|
||||
|
||||
Changes to google-api-go-client must be reviewed before they are submitted,
|
||||
no matter who makes the change.
|
||||
A custom git command called `git-codereview`,
|
||||
discussed below, helps manage the code review process through a Google-hosted
|
||||
[instance](https://code-review.googlesource.com/) of the code review
|
||||
system called [Gerrit](https://code.google.com/p/gerrit/).
|
||||
|
||||
### Set up authentication for code review
|
||||
|
||||
The Git code hosting server and Gerrit code review server both use a Google
|
||||
Account to authenticate. You therefore need a Google Account to proceed.
|
||||
(If you can use the account to
|
||||
[sign in at google.com](https://www.google.com/accounts/Login),
|
||||
you can use it to sign in to the code review server.)
|
||||
The email address you use with the code review system
|
||||
needs to be added to the [`CONTRIBUTORS`](/CONTRIBUTORS) file
|
||||
with your first code review.
|
||||
You can [create a Google Account](https://www.google.com/accounts/NewAccount)
|
||||
associated with any address where you receive email.
|
||||
|
||||
Visit the site [code.googlesource.com](https://code.googlesource.com)
|
||||
and log in using your Google Account.
|
||||
Click on the "Generate Password" link that appears at the top of the page.
|
||||
|
||||
Click the radio button that says "Only `code.googlesource.com`"
|
||||
to use this authentication token only for the google-api-go-client project.
|
||||
|
||||
Further down the page is a box containing commands to install
|
||||
the authentication cookie in file called `.gitcookies` in your home
|
||||
directory.
|
||||
Copy the text for the commands into a Unix shell window to execute it.
|
||||
That will install the authentication token.
|
||||
|
||||
(If you are on a Windows computer, you should instead follow the instructions
|
||||
in the yellow box to run the command.)
|
||||
|
||||
### Register with Gerrit
|
||||
|
||||
Now that you have a Google account and the authentication token,
|
||||
you need to register your account with Gerrit, the code review system.
|
||||
To do this, visit [golang.org/cl](https://golang.org/cl)
|
||||
and log in using the same Google Account you used above.
|
||||
That is all that is required.
|
||||
|
||||
### Install the git-codereview command
|
||||
|
||||
Now install the `git-codereview` command by running,
|
||||
|
||||
```
|
||||
go get -u golang.org/x/review/git-codereview
|
||||
```
|
||||
|
||||
Make sure `git-codereview` is installed in your shell path, so that the
|
||||
`git` command can find it. Check that
|
||||
|
||||
```
|
||||
$ git codereview help
|
||||
```
|
||||
|
||||
prints help text, not an error.
|
||||
|
||||
Note to Git aficionados: The `git-codereview` command is not required to
|
||||
upload and manage Gerrit code reviews. For those who prefer plain Git, the text
|
||||
below gives the Git equivalent of each git-codereview command. If you do use plain
|
||||
Git, note that you still need the commit hooks that the git-codereview command
|
||||
configures; those hooks add a Gerrit `Change-Id` line to the commit
|
||||
message and check that all Go source files have been formatted with gofmt. Even
|
||||
if you intend to use plain Git for daily work, install the hooks in a new Git
|
||||
checkout by running `git-codereview hooks`.
|
||||
|
||||
### Set up git aliases
|
||||
|
||||
The `git-codereview` command can be run directly from the shell
|
||||
by typing, for instance,
|
||||
|
||||
```
|
||||
$ git codereview sync
|
||||
```
|
||||
|
||||
but it is more convenient to set up aliases for `git-codereview`'s own
|
||||
subcommands, so that the above becomes,
|
||||
|
||||
```
|
||||
$ git sync
|
||||
```
|
||||
|
||||
The `git-codereview` subcommands have been chosen to be distinct from
|
||||
Git's own, so it's safe to do so.
|
||||
|
||||
The aliases are optional, but in the rest of this document we will assume
|
||||
they are installed.
|
||||
To install them, copy this text into your Git configuration file
|
||||
(usually `.gitconfig` in your home directory):
|
||||
|
||||
```
|
||||
[alias]
|
||||
change = codereview change
|
||||
gofmt = codereview gofmt
|
||||
mail = codereview mail
|
||||
pending = codereview pending
|
||||
submit = codereview submit
|
||||
sync = codereview sync
|
||||
```
|
||||
|
||||
### Understanding the git-codereview command
|
||||
|
||||
After installing the `git-codereview` command, you can run
|
||||
|
||||
```
|
||||
$ git codereview help
|
||||
```
|
||||
|
||||
to learn more about its commands.
|
||||
You can also read the [command documentation](https://godoc.org/golang.org/x/review/git-codereview).
|
||||
|
||||
### Switch to the master branch
|
||||
|
||||
New changes should
|
||||
only be made based on the master branch.
|
||||
Before making a change, make sure you start on the master branch:
|
||||
|
||||
```
|
||||
$ git checkout master
|
||||
$ git sync
|
||||
````
|
||||
|
||||
(In Git terms, `git sync` runs
|
||||
`git pull -r`.)
|
||||
|
||||
### Make a change
|
||||
|
||||
The entire checked-out tree is writable.
|
||||
Once you have edited files, you must tell Git that they have been modified.
|
||||
You must also tell Git about any files that are added, removed, or renamed files.
|
||||
These operations are done with the usual Git commands,
|
||||
`git add`,
|
||||
`git rm`,
|
||||
and
|
||||
`git mv`.
|
||||
|
||||
If you wish to checkpoint your work, or are ready to send the code out for review, run
|
||||
|
||||
```
|
||||
$ git change <branch>
|
||||
```
|
||||
|
||||
from any directory in your google-api-go-client repository to commit the changes so far.
|
||||
The name `<branch>` is an arbitrary one you choose to identify the
|
||||
local branch containing your changes.
|
||||
|
||||
(In Git terms, `git change <branch>`
|
||||
runs `git checkout -b branch`,
|
||||
then `git branch --set-upstream-to origin/master`,
|
||||
then `git commit`.)
|
||||
|
||||
Git will open a change description file in your editor.
|
||||
(It uses the editor named by the `$EDITOR` environment variable,
|
||||
`vi` by default.)
|
||||
The file will look like:
|
||||
|
||||
```
|
||||
# Please enter the commit message for your changes. Lines starting
|
||||
# with '#' will be ignored, and an empty message aborts the commit.
|
||||
# On branch foo
|
||||
# Changes not staged for commit:
|
||||
# modified: editedfile.go
|
||||
#
|
||||
```
|
||||
|
||||
At the beginning of this file is a blank line; replace it
|
||||
with a thorough description of your change.
|
||||
The first line of the change description is conventionally a one-line
|
||||
summary of the change, prefixed by `google-api-go-client:`,
|
||||
and is used as the subject for code review mail.
|
||||
The rest of the
|
||||
description elaborates and should provide context for the
|
||||
change and explain what it does.
|
||||
If there is a helpful reference, mention it here.
|
||||
|
||||
After editing, the template might now read:
|
||||
|
||||
```
|
||||
math: improved Sin, Cos and Tan precision for very large arguments
|
||||
|
||||
The existing implementation has poor numerical properties for
|
||||
large arguments, so use the McGillicutty algorithm to improve
|
||||
accuracy above 1e10.
|
||||
|
||||
The algorithm is described at http://wikipedia.org/wiki/McGillicutty_Algorithm
|
||||
|
||||
Fixes #54
|
||||
|
||||
# Please enter the commit message for your changes. Lines starting
|
||||
# with '#' will be ignored, and an empty message aborts the commit.
|
||||
# On branch foo
|
||||
# Changes not staged for commit:
|
||||
# modified: editedfile.go
|
||||
#
|
||||
```
|
||||
|
||||
The commented section of the file lists all the modified files in your client.
|
||||
It is best to keep unrelated changes in different change lists,
|
||||
so if you see a file listed that should not be included, abort
|
||||
the command and move that file to a different branch.
|
||||
|
||||
The special notation "Fixes #54" associates the change with issue 54 in the
|
||||
[google-api-go-client issue tracker](https://github.com/google/google-api-go-client/issues/54).
|
||||
When this change is eventually submitted, the issue
|
||||
tracker will automatically mark the issue as fixed.
|
||||
(There are several such conventions, described in detail in the
|
||||
[GitHub Issue Tracker documentation](https://help.github.com/articles/closing-issues-via-commit-messages/).)
|
||||
|
||||
Once you have finished writing the commit message,
|
||||
save the file and exit the editor.
|
||||
|
||||
If you wish to do more editing, re-stage your changes using
|
||||
`git add`, and then run
|
||||
|
||||
```
|
||||
$ git change
|
||||
```
|
||||
|
||||
to update the change description and incorporate the staged changes. The
|
||||
change description contains a `Change-Id` line near the bottom,
|
||||
added by a Git commit hook during the initial
|
||||
`git change`.
|
||||
That line is used by Gerrit to match successive uploads of the same change.
|
||||
Do not edit or delete it.
|
||||
|
||||
(In Git terms, `git change` with no branch name
|
||||
runs `git commit --amend`.)
|
||||
|
||||
### Mail the change for review
|
||||
|
||||
Once the change is ready, mail it out for review:
|
||||
|
||||
```
|
||||
$ git mail
|
||||
```
|
||||
|
||||
You can specify a reviewer or CC interested parties
|
||||
using the `-r` or `-cc` options.
|
||||
Both accept a comma-separated list of email addresses:
|
||||
|
||||
```
|
||||
$ git mail -r joe@golang.org -cc mabel@example.com,math-nuts@swtch.com
|
||||
```
|
||||
|
||||
Unless explicitly told otherwise, such as in the discussion leading
|
||||
up to sending in the change list, please specify
|
||||
`bradfitz@golang.org`, `gmlewis@google.com`, or
|
||||
`mcgreevy@golang.org` as a reviewer.
|
||||
|
||||
(In Git terms, `git mail` pushes the local committed
|
||||
changes to Gerrit using `git push origin HEAD:refs/for/master`.)
|
||||
|
||||
If your change relates to an open issue, please add a comment to the issue
|
||||
announcing your proposed fix, including a link to your CL.
|
||||
|
||||
The code review server assigns your change an issue number and URL,
|
||||
which `git mail` will print, something like:
|
||||
|
||||
```
|
||||
remote: New Changes:
|
||||
remote: https://code-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments
|
||||
```
|
||||
|
||||
### Reviewing code
|
||||
|
||||
Running `git mail` will send an email to you and the
|
||||
reviewers asking them to visit the issue's URL and make comments on the change.
|
||||
When done, the reviewer adds comments through the Gerrit user interface
|
||||
and clicks "Reply" to send comments back.
|
||||
You will receive a mail notification when this happens.
|
||||
You must reply through the web interface.
|
||||
|
||||
### Revise and upload
|
||||
|
||||
You must respond to review comments through the web interface.
|
||||
|
||||
When you have revised the code and are ready for another round of review,
|
||||
stage those changes and use `git change` to update the
|
||||
commit.
|
||||
To send the update change list for another round of review,
|
||||
run `git mail` again.
|
||||
|
||||
The reviewer can comment on the new copy, and the process repeats.
|
||||
The reviewer approves the change by giving it a positive score
|
||||
(+1 or +2) and replying `LGTM`: looks good to me.
|
||||
|
||||
You can see a list of your pending changes by running
|
||||
`git pending`, and switch between change branches with
|
||||
`git change <branch>`.
|
||||
|
||||
### Synchronize your client
|
||||
|
||||
While you were working, others might have submitted changes to the repository.
|
||||
To update your local branch, run
|
||||
|
||||
```
|
||||
$ git sync
|
||||
```
|
||||
|
||||
(In git terms, `git sync` runs
|
||||
`git pull -r`.)
|
||||
|
||||
If files you were editing have changed, Git does its best to merge the
|
||||
remote changes into your local changes.
|
||||
It may leave some files to merge by hand.
|
||||
|
||||
For example, suppose you have edited `sin.go` but
|
||||
someone else has committed an independent change.
|
||||
When you run `git sync`,
|
||||
you will get the (scary-looking) output:
|
||||
|
||||
```
|
||||
$ git sync
|
||||
Failed to merge in the changes.
|
||||
Patch failed at 0023 math: improved Sin, Cos and Tan precision for very large arguments
|
||||
The copy of the patch that failed is found in:
|
||||
/home/you/repo/.git/rebase-apply/patch
|
||||
|
||||
When you have resolved this problem, run "git rebase --continue".
|
||||
If you prefer to skip this patch, run "git rebase --skip" instead.
|
||||
To check out the original branch and stop rebasing, run "git rebase --abort".
|
||||
```
|
||||
|
||||
|
||||
If this happens, run
|
||||
|
||||
```
|
||||
$ git status
|
||||
```
|
||||
|
||||
to see which files failed to merge.
|
||||
The output will look something like this:
|
||||
|
||||
```
|
||||
rebase in progress; onto a24c3eb
|
||||
You are currently rebasing branch 'mcgillicutty' on 'a24c3eb'.
|
||||
(fix conflicts and then run "git rebase --continue")
|
||||
(use "git rebase --skip" to skip this patch)
|
||||
(use "git rebase --abort" to check out the original branch)
|
||||
|
||||
Unmerged paths:
|
||||
(use "git reset HEAD <file>..." to unstage)
|
||||
(use "git add <file>..." to mark resolution)
|
||||
|
||||
_both modified: sin.go_
|
||||
```
|
||||
|
||||
|
||||
The only important part in that transcript is the italicized "both modified"
|
||||
line: Git failed to merge your changes with the conflicting change.
|
||||
When this happens, Git leaves both sets of edits in the file,
|
||||
with conflicts marked by `<<<<<<<` and
|
||||
`>>>>>>>`.
|
||||
It is now your job to edit the file to combine them.
|
||||
Continuing the example, searching for those strings in `sin.go`
|
||||
might turn up:
|
||||
|
||||
```
|
||||
arg = scale(arg)
|
||||
<<<<<<< HEAD
|
||||
if arg > 1e9 {
|
||||
=======
|
||||
if arg > 1e10 {
|
||||
>>>>>>> mcgillicutty
|
||||
largeReduce(arg)
|
||||
```
|
||||
|
||||
Git doesn't show it, but suppose the original text that both edits
|
||||
started with was 1e8; you changed it to 1e10 and the other change to 1e9,
|
||||
so the correct answer might now be 1e10. First, edit the section
|
||||
to remove the markers and leave the correct code:
|
||||
|
||||
```
|
||||
arg = scale(arg)
|
||||
if arg > 1e10 {
|
||||
largeReduce(arg)
|
||||
```
|
||||
|
||||
Then tell Git that the conflict is resolved by running
|
||||
|
||||
```
|
||||
$ git add sin.go
|
||||
```
|
||||
|
||||
If you had been editing the file, say for debugging, but do not
|
||||
care to preserve your changes, you can run
|
||||
`git reset HEAD sin.go`
|
||||
to abandon your changes.
|
||||
Then run `git rebase --continue` to
|
||||
restore the change commit.
|
||||
|
||||
### Reviewing code by others
|
||||
|
||||
You can import a change proposed by someone else into your local Git repository.
|
||||
On the Gerrit review page, click the "Download ▼" link in the upper right
|
||||
corner, copy the "Checkout" command and run it from your local Git repo.
|
||||
It should look something like this:
|
||||
|
||||
```
|
||||
$ git fetch https://code.googlesource.com/review refs/changes/21/1221/1 && git checkout FETCH_HEAD
|
||||
```
|
||||
|
||||
To revert, change back to the branch you were working in.
|
||||
|
||||
### Submit the change after the review
|
||||
|
||||
After the code has been `LGTM`'ed, an approver may
|
||||
submit it to the master branch using the Gerrit UI.
|
||||
There is a "Submit" button on the web page for the change
|
||||
that appears once the change is approved (marked +2).
|
||||
|
||||
This checks the change into the repository.
|
||||
The change description will include a link to the code review,
|
||||
and the code review will be updated with a link to the change
|
||||
in the repository.
|
||||
Since the method used to integrate the changes is "Cherry Pick",
|
||||
the commit hashes in the repository will be changed by
|
||||
the submit operation.
|
||||
|
||||
### More information
|
||||
|
||||
In addition to the information here, the Go community maintains a [CodeReview](https://golang.org/wiki/CodeReview) wiki page.
|
||||
Feel free to contribute to this page as you learn the review process.
|
||||
|
||||
## Contributors
|
||||
|
||||
Files in the google-api-go-client repository don't list author names,
|
||||
both to avoid clutter and to avoid having to keep the lists up to date.
|
||||
Instead, please add your name to the [`CONTRIBUTORS`](/CONTRIBUTORS)
|
||||
file as your first code review, keeping the names in sorted order.
|
||||
55
vendor/google.golang.org/api/CONTRIBUTORS
generated
vendored
Normal file
55
vendor/google.golang.org/api/CONTRIBUTORS
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# This is the official list of people who can contribute
|
||||
# (and typically have contributed) code to the repository.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# The submission process automatically checks to make sure
|
||||
# that people submitting code are listed in this file (by email address).
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# https://cla.developers.google.com/about/google-individual
|
||||
# https://cla.developers.google.com/about/google-corporate
|
||||
#
|
||||
# The CLA can be filled out on the web:
|
||||
#
|
||||
# https://cla.developers.google.com/
|
||||
#
|
||||
# When adding J Random Contributor's name to this file,
|
||||
# either J's name or J's organization's name should be
|
||||
# added to the AUTHORS file, depending on whether the
|
||||
# individual or corporate CLA was used.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
#
|
||||
# An entry with two email addresses specifies that the
|
||||
# first address should be used in the submit logs and
|
||||
# that the second address should be recognized as the
|
||||
# same person when interacting with Rietveld.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Alain Vongsouvanhalainv <alainv@google.com>
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Brad Fitzpatrick <bradfitz@golang.org>
|
||||
Eric Koleda <ekoleda+devrel@googlers.com>
|
||||
Francesc Campoy <campoy@golang.org>
|
||||
Garrick Evans <garrick@google.com>
|
||||
Glenn Lewis <gmlewis@google.com>
|
||||
Ivan Krasin <krasin@golang.org>
|
||||
Jason Hall <jasonhall@google.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
Kostik Shtoyk <kostik@google.com>
|
||||
Kunpei Sakai <namusyaka@gmail.com>
|
||||
Matthew Whisenhunt <matt.whisenhunt@gmail.com>
|
||||
Michael McGreevy <mcgreevy@golang.org>
|
||||
Nick Craig-Wood <nickcw@gmail.com>
|
||||
Robbie Trencheny <me@robbiet.us>
|
||||
Ross Light <light@google.com>
|
||||
Sarah Adams <shadams@google.com>
|
||||
Scott Van Woudenberg <scottvw@google.com>
|
||||
Takashi Matsuo <tmatsuo@google.com>
|
||||
146
vendor/google.golang.org/api/GettingStarted.md
generated
vendored
Normal file
146
vendor/google.golang.org/api/GettingStarted.md
generated
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# Getting Started with the Google APIs for Go
|
||||
|
||||
## Getting Started
|
||||
|
||||
This is a quick walk-through of how to get started with the Google APIs for Go.
|
||||
|
||||
## Background
|
||||
|
||||
The first thing to understand is that the Google API libraries are auto-generated for
|
||||
each language, including Go, so they may not feel like 100% natural for any language.
|
||||
The Go versions are pretty natural, but please forgive any small non-idiomatic things.
|
||||
(Suggestions welcome, though!)
|
||||
|
||||
## Installing
|
||||
|
||||
Pick an API and a version of that API to install.
|
||||
You can find the complete list by looking at the
|
||||
[directories here](https://github.com/google/google-api-go-client/tree/master/).
|
||||
|
||||
For example, let's install the
|
||||
[urlshortener's version 1 API](https://godoc.org/google.golang.org/api/urlshortener/v1):
|
||||
|
||||
```
|
||||
$ go get -u google.golang.org/api/urlshortener/v1
|
||||
```
|
||||
|
||||
Now it's ready for use in your code.
|
||||
|
||||
## Using
|
||||
|
||||
Once you've installed a library, you import it like this:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/urlshortener/v1"
|
||||
)
|
||||
```
|
||||
|
||||
The package name, if you don't override it on your import line, is the name of the
|
||||
API without the version number. In the case above, just `urlshortener`.
|
||||
|
||||
## Instantiating
|
||||
|
||||
Each API has a `New` function taking an `*http.Client` and returning an API-specific `*Service`.
|
||||
|
||||
You create the service like:
|
||||
|
||||
```go
|
||||
svc, err := urlshortener.New(httpClient)
|
||||
```
|
||||
|
||||
## OAuth HTTP Client
|
||||
|
||||
The HTTP client you pass in to the service must be one that automatically adds
|
||||
Google-supported Authorization information to the requests.
|
||||
|
||||
There are several ways to do authentication. They will all involve the package
|
||||
[golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2) in some way.
|
||||
|
||||
### 3-legged OAuth
|
||||
|
||||
For 3-legged OAuth (your application redirecting a user through a website to get a
|
||||
token giving your application access to that user's resources), you will need to
|
||||
create an oauth2.Config,
|
||||
|
||||
|
||||
```go
|
||||
var config = &oauth2.Config{
|
||||
ClientID: "", // from https://console.developers.google.com/project/<your-project-id>/apiui/credential
|
||||
ClientSecret: "", // from https://console.developers.google.com/project/<your-project-id>/apiui/credential
|
||||
Endpoint: google.Endpoint,
|
||||
Scopes: []string{urlshortener.UrlshortenerScope},
|
||||
}
|
||||
```
|
||||
|
||||
... and then use the AuthCodeURL, Exchange, and Client methods on it.
|
||||
For an example, see: https://godoc.org/golang.org/x/oauth2#example-Config
|
||||
|
||||
For the redirect URL, see
|
||||
https://developers.google.com/identity/protocols/OAuth2InstalledApp#choosingredirecturi
|
||||
|
||||
### Service Accounts
|
||||
|
||||
To use a Google service account, or the GCE metadata service, see
|
||||
the [golang.org/x/oauth2/google](https://godoc.org/golang.org/x/oauth2/google) package.
|
||||
In particular, see [google.DefaultClient](https://godoc.org/golang.org/x/oauth2/google#DefaultClient).
|
||||
|
||||
### Using API Keys
|
||||
|
||||
Some APIs require passing API keys from your application.
|
||||
To do this, you can use
|
||||
[transport.APIKey](https://godoc.org/google.golang.org/api/googleapi/transport#APIKey):
|
||||
|
||||
```go
|
||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{
|
||||
Transport: &transport.APIKey{Key: developerKey},
|
||||
})
|
||||
oauthConfig := &oauth2.Config{ .... }
|
||||
var token *oauth2.Token = .... // via cache, or oauthConfig.Exchange
|
||||
httpClient := oauthConfig.Client(ctx, token)
|
||||
svc, err := urlshortener.New(httpClient)
|
||||
...
|
||||
```
|
||||
|
||||
## Using the Service
|
||||
|
||||
Each service contains zero or more methods and zero or more sub-services.
|
||||
The sub-services related to a specific type of "Resource".
|
||||
|
||||
Those sub-services then contain their own methods.
|
||||
|
||||
For instance, the urlshortener API has just the "Url" sub-service:
|
||||
|
||||
```go
|
||||
url, err := svc.Url.Get(shortURL).Do()
|
||||
if err != nil {
|
||||
...
|
||||
}
|
||||
fmt.Printf("The URL %s goes to %s\n", shortURL, url.LongUrl)
|
||||
```
|
||||
|
||||
For a more complete example, see
|
||||
[urlshortener.go](https://github.com/google/google-api-go-client/tree/master/examples/urlshortener.go)
|
||||
in the [examples directory](https://github.com/google/google-api-go-client/tree/master/examples/).
|
||||
(the examples use some functions in `main.go` in the same directory)
|
||||
|
||||
## Error Handling
|
||||
|
||||
Most errors returned by the `Do` methods of these clients will be of type
|
||||
[`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error).
|
||||
Use a type assertion to obtain the HTTP status code and other properties of the
|
||||
error:
|
||||
|
||||
```go
|
||||
url, err := svc.Url.Get(shortURL).Do()
|
||||
if err != nil {
|
||||
if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
27
vendor/google.golang.org/api/LICENSE
generated
vendored
Normal file
27
vendor/google.golang.org/api/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
13
vendor/google.golang.org/api/NOTES
generated
vendored
Normal file
13
vendor/google.golang.org/api/NOTES
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Discovery Service:
|
||||
https://developers.google.com/discovery/
|
||||
https://developers.google.com/discovery/v1/reference/
|
||||
|
||||
The "type" key:
|
||||
http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
|
||||
|
||||
The "format" key:
|
||||
http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.23
|
||||
https://developers.google.com/discovery/v1/type-format
|
||||
|
||||
Google JSON format docs:
|
||||
http://google-styleguide.googlecode.com/svn/trunk/jsoncstyleguide.xml
|
||||
103
vendor/google.golang.org/api/README.md
generated
vendored
Normal file
103
vendor/google.golang.org/api/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Google APIs Client Library for Go
|
||||
|
||||
## Getting Started
|
||||
|
||||
```
|
||||
$ go get google.golang.org/api/tasks/v1
|
||||
$ go get google.golang.org/api/moderator/v1
|
||||
$ go get google.golang.org/api/urlshortener/v1
|
||||
... etc ...
|
||||
```
|
||||
|
||||
and using:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"google.golang.org/api/urlshortener/v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
svc, err := urlshortener.New(http.DefaultClient)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
* For a longer tutorial, see the [Getting Started guide](https://github.com/google/google-api-go-client/blob/master/GettingStarted.md).
|
||||
* For examples, see the [examples directory](https://github.com/google/google-api-go-client/tree/master/examples).
|
||||
* For support, use the [golang-nuts](https://groups.google.com/group/golang-nuts) mailing list.
|
||||
|
||||
## Status
|
||||
[](https://godoc.org/google.golang.org/api)
|
||||
|
||||
These are auto-generated Go libraries from the Google Discovery Service's JSON description files of the available "new style" Google APIs.
|
||||
|
||||
Due to the auto-generated nature of this collection of libraries, complete APIs or specific versions can appear or go away without notice.
|
||||
As a result, you should always locally vendor any API(s) that your code relies upon.
|
||||
|
||||
These client libraries are officially supported by Google. However, the libraries are considered complete and are in maintenance mode. This means that we will address critical bugs and security issues but will not add any new features.
|
||||
|
||||
If you're working with Google Cloud Platform APIs such as Datastore or Pub/Sub,
|
||||
consider using the
|
||||
[Cloud Client Libraries for Go](https://github.com/GoogleCloudPlatform/google-cloud-go)
|
||||
instead. These are the new and
|
||||
idiomatic Go libraries targeted specifically at Google Cloud Platform Services.
|
||||
|
||||
The generator itself and the code it produces are beta. Some APIs are
|
||||
alpha/beta, and indicated as such in the import path (e.g.,
|
||||
"google.golang.org/api/someapi/v1alpha").
|
||||
|
||||
## Application Default Credentials Example
|
||||
|
||||
Application Default Credentials provide a simplified way to obtain credentials
|
||||
for authenticating with Google APIs.
|
||||
|
||||
The Application Default Credentials authenticate as the application itself,
|
||||
which make them great for working with Google Cloud APIs like Storage or
|
||||
Datastore. They are the recommended form of authentication when building
|
||||
applications that run on Google Compute Engine or Google App Engine.
|
||||
|
||||
Default credentials are provided by the `golang.org/x/oauth2/google` package. To use them, add the following import:
|
||||
|
||||
```go
|
||||
import "golang.org/x/oauth2/google"
|
||||
```
|
||||
|
||||
Some credentials types require you to specify scopes, and service entry points may not inject them. If you encounter this situation you may need to specify scopes as follows:
|
||||
|
||||
```go
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Use oauth2.NoContext if there isn't a good context to pass in.
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := google.DefaultClient(ctx, compute.ComputeScope)
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
computeService, err := compute.New(client)
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you need a `oauth2.TokenSource`, use the `DefaultTokenSource` function:
|
||||
|
||||
```go
|
||||
ts, err := google.DefaultTokenSource(ctx, scope1, scope2, ...)
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
client := oauth2.NewClient(ctx, ts)
|
||||
```
|
||||
|
||||
See also: [golang.org/x/oauth2/google](https://godoc.org/golang.org/x/oauth2/google) package documentation.
|
||||
2
vendor/google.golang.org/api/TODO
generated
vendored
Normal file
2
vendor/google.golang.org/api/TODO
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Moved to:
|
||||
https://github.com/google/google-api-go-client/issues
|
||||
3363
vendor/google.golang.org/api/api-list.json
generated
vendored
Normal file
3363
vendor/google.golang.org/api/api-list.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
0
vendor/google.golang.org/api/key.json.enc
generated
vendored
Normal file
0
vendor/google.golang.org/api/key.json.enc
generated
vendored
Normal file
349
vendor/google.golang.org/api/support/bundler/bundler.go
generated
vendored
Normal file
349
vendor/google.golang.org/api/support/bundler/bundler.go
generated
vendored
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package bundler supports bundling (batching) of items. Bundling amortizes an
|
||||
// action with fixed costs over multiple items. For example, if an API provides
|
||||
// an RPC that accepts a list of items as input, but clients would prefer
|
||||
// adding items one at a time, then a Bundler can accept individual items from
|
||||
// the client and bundle many of them into a single RPC.
|
||||
//
|
||||
// This package is experimental and subject to change without notice.
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultDelayThreshold = time.Second
|
||||
DefaultBundleCountThreshold = 10
|
||||
DefaultBundleByteThreshold = 1e6 // 1M
|
||||
DefaultBufferedByteLimit = 1e9 // 1G
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrOverflow indicates that Bundler's stored bytes exceeds its BufferedByteLimit.
|
||||
ErrOverflow = errors.New("bundler reached buffered byte limit")
|
||||
|
||||
// ErrOversizedItem indicates that an item's size exceeds the maximum bundle size.
|
||||
ErrOversizedItem = errors.New("item size exceeds bundle byte limit")
|
||||
)
|
||||
|
||||
// A Bundler collects items added to it into a bundle until the bundle
|
||||
// exceeds a given size, then calls a user-provided function to handle the bundle.
|
||||
type Bundler struct {
|
||||
// Starting from the time that the first message is added to a bundle, once
|
||||
// this delay has passed, handle the bundle. The default is DefaultDelayThreshold.
|
||||
DelayThreshold time.Duration
|
||||
|
||||
// Once a bundle has this many items, handle the bundle. Since only one
|
||||
// item at a time is added to a bundle, no bundle will exceed this
|
||||
// threshold, so it also serves as a limit. The default is
|
||||
// DefaultBundleCountThreshold.
|
||||
BundleCountThreshold int
|
||||
|
||||
// Once the number of bytes in current bundle reaches this threshold, handle
|
||||
// the bundle. The default is DefaultBundleByteThreshold. This triggers handling,
|
||||
// but does not cap the total size of a bundle.
|
||||
BundleByteThreshold int
|
||||
|
||||
// The maximum size of a bundle, in bytes. Zero means unlimited.
|
||||
BundleByteLimit int
|
||||
|
||||
// The maximum number of bytes that the Bundler will keep in memory before
|
||||
// returning ErrOverflow. The default is DefaultBufferedByteLimit.
|
||||
BufferedByteLimit int
|
||||
|
||||
// The maximum number of handler invocations that can be running at once.
|
||||
// The default is 1.
|
||||
HandlerLimit int
|
||||
|
||||
handler func(interface{}) // called to handle a bundle
|
||||
itemSliceZero reflect.Value // nil (zero value) for slice of items
|
||||
flushTimer *time.Timer // implements DelayThreshold
|
||||
|
||||
mu sync.Mutex
|
||||
sem *semaphore.Weighted // enforces BufferedByteLimit
|
||||
semOnce sync.Once
|
||||
curBundle bundle // incoming items added to this bundle
|
||||
|
||||
// Each bundle is assigned a unique ticket that determines the order in which the
|
||||
// handler is called. The ticket is assigned with mu locked, but waiting for tickets
|
||||
// to be handled is done via mu2 and cond, below.
|
||||
nextTicket uint64 // next ticket to be assigned
|
||||
|
||||
mu2 sync.Mutex
|
||||
cond *sync.Cond
|
||||
nextHandled uint64 // next ticket to be handled
|
||||
|
||||
// In this implementation, active uses space proportional to HandlerLimit, and
|
||||
// waitUntilAllHandled takes time proportional to HandlerLimit each time an acquire
|
||||
// or release occurs, so large values of HandlerLimit max may cause performance
|
||||
// issues.
|
||||
active map[uint64]bool // tickets of bundles actively being handled
|
||||
}
|
||||
|
||||
type bundle struct {
|
||||
items reflect.Value // slice of item type
|
||||
size int // size in bytes of all items
|
||||
}
|
||||
|
||||
// NewBundler creates a new Bundler.
|
||||
//
|
||||
// itemExample is a value of the type that will be bundled. For example, if you
|
||||
// want to create bundles of *Entry, you could pass &Entry{} for itemExample.
|
||||
//
|
||||
// handler is a function that will be called on each bundle. If itemExample is
|
||||
// of type T, the argument to handler is of type []T. handler is always called
|
||||
// sequentially for each bundle, and never in parallel.
|
||||
//
|
||||
// Configure the Bundler by setting its thresholds and limits before calling
|
||||
// any of its methods.
|
||||
func NewBundler(itemExample interface{}, handler func(interface{})) *Bundler {
|
||||
b := &Bundler{
|
||||
DelayThreshold: DefaultDelayThreshold,
|
||||
BundleCountThreshold: DefaultBundleCountThreshold,
|
||||
BundleByteThreshold: DefaultBundleByteThreshold,
|
||||
BufferedByteLimit: DefaultBufferedByteLimit,
|
||||
HandlerLimit: 1,
|
||||
|
||||
handler: handler,
|
||||
itemSliceZero: reflect.Zero(reflect.SliceOf(reflect.TypeOf(itemExample))),
|
||||
active: map[uint64]bool{},
|
||||
}
|
||||
b.curBundle.items = b.itemSliceZero
|
||||
b.cond = sync.NewCond(&b.mu2)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bundler) initSemaphores() {
|
||||
// Create the semaphores lazily, because the user may set limits
|
||||
// after NewBundler.
|
||||
b.semOnce.Do(func() {
|
||||
b.sem = semaphore.NewWeighted(int64(b.BufferedByteLimit))
|
||||
})
|
||||
}
|
||||
|
||||
// Add adds item to the current bundle. It marks the bundle for handling and
|
||||
// starts a new one if any of the thresholds or limits are exceeded.
|
||||
//
|
||||
// If the item's size exceeds the maximum bundle size (Bundler.BundleByteLimit), then
|
||||
// the item can never be handled. Add returns ErrOversizedItem in this case.
|
||||
//
|
||||
// If adding the item would exceed the maximum memory allowed
|
||||
// (Bundler.BufferedByteLimit) or an AddWait call is blocked waiting for
|
||||
// memory, Add returns ErrOverflow.
|
||||
//
|
||||
// Add never blocks.
|
||||
func (b *Bundler) Add(item interface{}, size int) error {
|
||||
// If this item exceeds the maximum size of a bundle,
|
||||
// we can never send it.
|
||||
if b.BundleByteLimit > 0 && size > b.BundleByteLimit {
|
||||
return ErrOversizedItem
|
||||
}
|
||||
// If adding this item would exceed our allotted memory
|
||||
// footprint, we can't accept it.
|
||||
// (TryAcquire also returns false if anything is waiting on the semaphore,
|
||||
// so calls to Add and AddWait shouldn't be mixed.)
|
||||
b.initSemaphores()
|
||||
if !b.sem.TryAcquire(int64(size)) {
|
||||
return ErrOverflow
|
||||
}
|
||||
b.add(item, size)
|
||||
return nil
|
||||
}
|
||||
|
||||
// add adds item to the current bundle. It marks the bundle for handling and
|
||||
// starts a new one if any of the thresholds or limits are exceeded.
|
||||
func (b *Bundler) add(item interface{}, size int) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
// If adding this item to the current bundle would cause it to exceed the
|
||||
// maximum bundle size, close the current bundle and start a new one.
|
||||
if b.BundleByteLimit > 0 && b.curBundle.size+size > b.BundleByteLimit {
|
||||
b.startFlushLocked()
|
||||
}
|
||||
// Add the item.
|
||||
b.curBundle.items = reflect.Append(b.curBundle.items, reflect.ValueOf(item))
|
||||
b.curBundle.size += size
|
||||
|
||||
// Start a timer to flush the item if one isn't already running.
|
||||
// startFlushLocked clears the timer and closes the bundle at the same time,
|
||||
// so we only allocate a new timer for the first item in each bundle.
|
||||
// (We could try to call Reset on the timer instead, but that would add a lot
|
||||
// of complexity to the code just to save one small allocation.)
|
||||
if b.flushTimer == nil {
|
||||
b.flushTimer = time.AfterFunc(b.DelayThreshold, b.Flush)
|
||||
}
|
||||
|
||||
// If the current bundle equals the count threshold, close it.
|
||||
if b.curBundle.items.Len() == b.BundleCountThreshold {
|
||||
b.startFlushLocked()
|
||||
}
|
||||
// If the current bundle equals or exceeds the byte threshold, close it.
|
||||
if b.curBundle.size >= b.BundleByteThreshold {
|
||||
b.startFlushLocked()
|
||||
}
|
||||
}
|
||||
|
||||
// AddWait adds item to the current bundle. It marks the bundle for handling and
|
||||
// starts a new one if any of the thresholds or limits are exceeded.
|
||||
//
|
||||
// If the item's size exceeds the maximum bundle size (Bundler.BundleByteLimit), then
|
||||
// the item can never be handled. AddWait returns ErrOversizedItem in this case.
|
||||
//
|
||||
// If adding the item would exceed the maximum memory allowed (Bundler.BufferedByteLimit),
|
||||
// AddWait blocks until space is available or ctx is done.
|
||||
//
|
||||
// Calls to Add and AddWait should not be mixed on the same Bundler.
|
||||
func (b *Bundler) AddWait(ctx context.Context, item interface{}, size int) error {
|
||||
// If this item exceeds the maximum size of a bundle,
|
||||
// we can never send it.
|
||||
if b.BundleByteLimit > 0 && size > b.BundleByteLimit {
|
||||
return ErrOversizedItem
|
||||
}
|
||||
// If adding this item would exceed our allotted memory footprint, block
|
||||
// until space is available. The semaphore is FIFO, so there will be no
|
||||
// starvation.
|
||||
b.initSemaphores()
|
||||
if err := b.sem.Acquire(ctx, int64(size)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Here, we've reserved space for item. Other goroutines can call AddWait
|
||||
// and even acquire space, but no one can take away our reservation
|
||||
// (assuming sem.Release is used correctly). So there is no race condition
|
||||
// resulting from locking the mutex after sem.Acquire returns.
|
||||
b.add(item, size)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush invokes the handler for all remaining items in the Bundler and waits
|
||||
// for it to return.
|
||||
func (b *Bundler) Flush() {
|
||||
b.mu.Lock()
|
||||
b.startFlushLocked()
|
||||
// Here, all bundles with tickets < b.nextTicket are
|
||||
// either finished or active. Those are the ones
|
||||
// we want to wait for.
|
||||
t := b.nextTicket
|
||||
b.mu.Unlock()
|
||||
b.initSemaphores()
|
||||
b.waitUntilAllHandled(t)
|
||||
}
|
||||
|
||||
func (b *Bundler) startFlushLocked() {
|
||||
if b.flushTimer != nil {
|
||||
b.flushTimer.Stop()
|
||||
b.flushTimer = nil
|
||||
}
|
||||
if b.curBundle.items.Len() == 0 {
|
||||
return
|
||||
}
|
||||
// Here, both semaphores must have been initialized.
|
||||
bun := b.curBundle
|
||||
b.curBundle = bundle{items: b.itemSliceZero}
|
||||
ticket := b.nextTicket
|
||||
b.nextTicket++
|
||||
go func() {
|
||||
defer func() {
|
||||
b.sem.Release(int64(bun.size))
|
||||
b.release(ticket)
|
||||
}()
|
||||
b.acquire(ticket)
|
||||
b.handler(bun.items.Interface())
|
||||
}()
|
||||
}
|
||||
|
||||
// acquire blocks until ticket is the next to be served, then returns. In order for N
|
||||
// acquire calls to return, the tickets must be in the range [0, N). A ticket must
|
||||
// not be presented to acquire more than once.
|
||||
func (b *Bundler) acquire(ticket uint64) {
|
||||
b.mu2.Lock()
|
||||
defer b.mu2.Unlock()
|
||||
if ticket < b.nextHandled {
|
||||
panic("bundler: acquire: arg too small")
|
||||
}
|
||||
for !(ticket == b.nextHandled && len(b.active) < b.HandlerLimit) {
|
||||
b.cond.Wait()
|
||||
}
|
||||
// Here,
|
||||
// ticket == b.nextHandled: the caller is the next one to be handled;
|
||||
// and len(b.active) < b.HandlerLimit: there is space available.
|
||||
b.active[ticket] = true
|
||||
b.nextHandled++
|
||||
// Broadcast, not Signal: although at most one acquire waiter can make progress,
|
||||
// there might be waiters in waitUntilAllHandled.
|
||||
b.cond.Broadcast()
|
||||
}
|
||||
|
||||
// If a ticket is used for a call to acquire, it must later be passed to release. A
|
||||
// ticket must not be presented to release more than once.
|
||||
func (b *Bundler) release(ticket uint64) {
|
||||
b.mu2.Lock()
|
||||
defer b.mu2.Unlock()
|
||||
if !b.active[ticket] {
|
||||
panic("bundler: release: not an active ticket")
|
||||
}
|
||||
delete(b.active, ticket)
|
||||
b.cond.Broadcast()
|
||||
}
|
||||
|
||||
// waitUntilAllHandled blocks until all tickets < n have called release, meaning
|
||||
// all bundles with tickets < n have been handled.
|
||||
func (b *Bundler) waitUntilAllHandled(n uint64) {
|
||||
// Proof of correctness of this function.
|
||||
// "N is acquired" means acquire(N) has returned.
|
||||
// "N is released" means release(N) has returned.
|
||||
// 1. If N is acquired, N-1 is acquired.
|
||||
// Follows from the loop test in acquire, and the fact
|
||||
// that nextHandled is incremented by 1.
|
||||
// 2. If nextHandled >= N, then N-1 is acquired.
|
||||
// Because we only increment nextHandled to N after N-1 is acquired.
|
||||
// 3. If nextHandled >= N, then all n < N is acquired.
|
||||
// Follows from #1 and #2.
|
||||
// 4. If N is acquired and N is not in active, then N is released.
|
||||
// Because we put N in active before acquire returns, and only
|
||||
// remove it when it is released.
|
||||
// Let min(active) be the smallest member of active, or infinity if active is empty.
|
||||
// 5. If nextHandled >= N and N <= min(active), then all n < N is released.
|
||||
// From nextHandled >= N and #3, all n < N is acquired.
|
||||
// N <= min(active) implies n < min(active) for all n < N. So all n < N is not in active.
|
||||
// So from #4, all n < N is released.
|
||||
// The loop test below is the antecedent of #5.
|
||||
b.mu2.Lock()
|
||||
defer b.mu2.Unlock()
|
||||
for !(b.nextHandled >= n && n <= min(b.active)) {
|
||||
b.cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// min returns the minimum value of the set s, or the largest uint64 if
|
||||
// s is empty.
|
||||
func min(s map[uint64]bool) uint64 {
|
||||
var m uint64 = math.MaxUint64
|
||||
for n := range s {
|
||||
if n < m {
|
||||
m = n
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
30
vendor/google.golang.org/appengine/.travis.yml
generated
vendored
30
vendor/google.golang.org/appengine/.travis.yml
generated
vendored
|
|
@ -1,24 +1,20 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
|
||||
go_import_path: google.golang.org/appengine
|
||||
|
||||
install:
|
||||
- go get -u -v $(go list -f '{{join .Imports "\n"}}{{"\n"}}{{join .TestImports "\n"}}' ./... | sort | uniq | grep -v appengine)
|
||||
- mkdir /tmp/sdk
|
||||
- curl -o /tmp/sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.40.zip"
|
||||
- unzip -q /tmp/sdk.zip -d /tmp/sdk
|
||||
- export PATH="$PATH:/tmp/sdk/go_appengine"
|
||||
- export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
|
||||
- ./travis_install.sh
|
||||
|
||||
script:
|
||||
- goapp version
|
||||
- go version
|
||||
- go test -v google.golang.org/appengine/...
|
||||
- go test -v -race google.golang.org/appengine/...
|
||||
- goapp test -v google.golang.org/appengine/...
|
||||
- ./travis_test.sh
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.8.x
|
||||
env: GOAPP=true
|
||||
- go: 1.9.x
|
||||
env: GOAPP=true
|
||||
- go: 1.10.x
|
||||
env: GOAPP=false
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
|
|
|
|||
18
vendor/google.golang.org/appengine/appengine.go
generated
vendored
18
vendor/google.golang.org/appengine/appengine.go
generated
vendored
|
|
@ -60,6 +60,24 @@ func IsDevAppServer() bool {
|
|||
return internal.IsDevAppServer()
|
||||
}
|
||||
|
||||
// IsStandard reports whether the App Engine app is running in the standard
|
||||
// environment. This includes both the first generation runtimes (<= Go 1.9)
|
||||
// and the second generation runtimes (>= Go 1.11).
|
||||
func IsStandard() bool {
|
||||
return internal.IsStandard()
|
||||
}
|
||||
|
||||
// IsFlex reports whether the App Engine app is running in the flexible environment.
|
||||
func IsFlex() bool {
|
||||
return internal.IsFlex()
|
||||
}
|
||||
|
||||
// IsAppEngine reports whether the App Engine app is running on App Engine, in either
|
||||
// the standard or flexible environment.
|
||||
func IsAppEngine() bool {
|
||||
return internal.IsAppEngine()
|
||||
}
|
||||
|
||||
// NewContext returns a context for an in-flight HTTP request.
|
||||
// This function is cheap.
|
||||
func NewContext(req *http.Request) context.Context {
|
||||
|
|
|
|||
3
vendor/google.golang.org/appengine/go.sum
generated
vendored
3
vendor/google.golang.org/appengine/go.sum
generated
vendored
|
|
@ -1,3 +1,6 @@
|
|||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225 h1:kNX+jCowfMYzvlSvJu5pQWEmyWFrBXJ3PBy10xKMXK8=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
|||
12
vendor/google.golang.org/appengine/internal/api.go
generated
vendored
12
vendor/google.golang.org/appengine/internal/api.go
generated
vendored
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
// +build go1.7
|
||||
|
||||
package internal
|
||||
|
||||
|
|
@ -130,7 +129,13 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
flushes++
|
||||
}
|
||||
c.pendingLogs.Unlock()
|
||||
go c.flushLog(false)
|
||||
flushed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(flushed)
|
||||
// Force a log flush, because with very short requests we
|
||||
// may not ever flush logs.
|
||||
c.flushLog(true)
|
||||
}()
|
||||
w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
|
||||
|
||||
// Avoid nil Write call if c.Write is never called.
|
||||
|
|
@ -140,6 +145,9 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
if c.outBody != nil {
|
||||
w.Write(c.outBody)
|
||||
}
|
||||
// Wait for the last flush to complete before returning,
|
||||
// otherwise the security ticket will not be valid.
|
||||
<-flushed
|
||||
}
|
||||
|
||||
func executeRequestSafely(c *context, r *http.Request) {
|
||||
|
|
|
|||
682
vendor/google.golang.org/appengine/internal/api_pre17.go
generated
vendored
682
vendor/google.golang.org/appengine/internal/api_pre17.go
generated
vendored
|
|
@ -1,682 +0,0 @@
|
|||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
// +build !go1.7
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
netcontext "golang.org/x/net/context"
|
||||
|
||||
basepb "google.golang.org/appengine/internal/base"
|
||||
logpb "google.golang.org/appengine/internal/log"
|
||||
remotepb "google.golang.org/appengine/internal/remote_api"
|
||||
)
|
||||
|
||||
const (
|
||||
apiPath = "/rpc_http"
|
||||
defaultTicketSuffix = "/default.20150612t184001.0"
|
||||
)
|
||||
|
||||
var (
|
||||
// Incoming headers.
|
||||
ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket")
|
||||
dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo")
|
||||
traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context")
|
||||
curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace")
|
||||
userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP")
|
||||
remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr")
|
||||
|
||||
// Outgoing headers.
|
||||
apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint")
|
||||
apiEndpointHeaderValue = []string{"app-engine-apis"}
|
||||
apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method")
|
||||
apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"}
|
||||
apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline")
|
||||
apiContentType = http.CanonicalHeaderKey("Content-Type")
|
||||
apiContentTypeValue = []string{"application/octet-stream"}
|
||||
logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count")
|
||||
|
||||
apiHTTPClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: limitDial,
|
||||
},
|
||||
}
|
||||
|
||||
defaultTicketOnce sync.Once
|
||||
defaultTicket string
|
||||
)
|
||||
|
||||
func apiURL() *url.URL {
|
||||
host, port := "appengine.googleapis.internal", "10001"
|
||||
if h := os.Getenv("API_HOST"); h != "" {
|
||||
host = h
|
||||
}
|
||||
if p := os.Getenv("API_PORT"); p != "" {
|
||||
port = p
|
||||
}
|
||||
return &url.URL{
|
||||
Scheme: "http",
|
||||
Host: host + ":" + port,
|
||||
Path: apiPath,
|
||||
}
|
||||
}
|
||||
|
||||
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
c := &context{
|
||||
req: r,
|
||||
outHeader: w.Header(),
|
||||
apiURL: apiURL(),
|
||||
}
|
||||
stopFlushing := make(chan int)
|
||||
|
||||
ctxs.Lock()
|
||||
ctxs.m[r] = c
|
||||
ctxs.Unlock()
|
||||
defer func() {
|
||||
ctxs.Lock()
|
||||
delete(ctxs.m, r)
|
||||
ctxs.Unlock()
|
||||
}()
|
||||
|
||||
// Patch up RemoteAddr so it looks reasonable.
|
||||
if addr := r.Header.Get(userIPHeader); addr != "" {
|
||||
r.RemoteAddr = addr
|
||||
} else if addr = r.Header.Get(remoteAddrHeader); addr != "" {
|
||||
r.RemoteAddr = addr
|
||||
} else {
|
||||
// Should not normally reach here, but pick a sensible default anyway.
|
||||
r.RemoteAddr = "127.0.0.1"
|
||||
}
|
||||
// The address in the headers will most likely be of these forms:
|
||||
// 123.123.123.123
|
||||
// 2001:db8::1
|
||||
// net/http.Request.RemoteAddr is specified to be in "IP:port" form.
|
||||
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
|
||||
// Assume the remote address is only a host; add a default port.
|
||||
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
|
||||
}
|
||||
|
||||
// Start goroutine responsible for flushing app logs.
|
||||
// This is done after adding c to ctx.m (and stopped before removing it)
|
||||
// because flushing logs requires making an API call.
|
||||
go c.logFlusher(stopFlushing)
|
||||
|
||||
executeRequestSafely(c, r)
|
||||
c.outHeader = nil // make sure header changes aren't respected any more
|
||||
|
||||
stopFlushing <- 1 // any logging beyond this point will be dropped
|
||||
|
||||
// Flush any pending logs asynchronously.
|
||||
c.pendingLogs.Lock()
|
||||
flushes := c.pendingLogs.flushes
|
||||
if len(c.pendingLogs.lines) > 0 {
|
||||
flushes++
|
||||
}
|
||||
c.pendingLogs.Unlock()
|
||||
go c.flushLog(false)
|
||||
w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
|
||||
|
||||
// Avoid nil Write call if c.Write is never called.
|
||||
if c.outCode != 0 {
|
||||
w.WriteHeader(c.outCode)
|
||||
}
|
||||
if c.outBody != nil {
|
||||
w.Write(c.outBody)
|
||||
}
|
||||
}
|
||||
|
||||
func executeRequestSafely(c *context, r *http.Request) {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
logf(c, 4, "%s", renderPanic(x)) // 4 == critical
|
||||
c.outCode = 500
|
||||
}
|
||||
}()
|
||||
|
||||
http.DefaultServeMux.ServeHTTP(c, r)
|
||||
}
|
||||
|
||||
func renderPanic(x interface{}) string {
|
||||
buf := make([]byte, 16<<10) // 16 KB should be plenty
|
||||
buf = buf[:runtime.Stack(buf, false)]
|
||||
|
||||
// Remove the first few stack frames:
|
||||
// this func
|
||||
// the recover closure in the caller
|
||||
// That will root the stack trace at the site of the panic.
|
||||
const (
|
||||
skipStart = "internal.renderPanic"
|
||||
skipFrames = 2
|
||||
)
|
||||
start := bytes.Index(buf, []byte(skipStart))
|
||||
p := start
|
||||
for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ {
|
||||
p = bytes.IndexByte(buf[p+1:], '\n') + p + 1
|
||||
if p < 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if p >= 0 {
|
||||
// buf[start:p+1] is the block to remove.
|
||||
// Copy buf[p+1:] over buf[start:] and shrink buf.
|
||||
copy(buf[start:], buf[p+1:])
|
||||
buf = buf[:len(buf)-(p+1-start)]
|
||||
}
|
||||
|
||||
// Add panic heading.
|
||||
head := fmt.Sprintf("panic: %v\n\n", x)
|
||||
if len(head) > len(buf) {
|
||||
// Extremely unlikely to happen.
|
||||
return head
|
||||
}
|
||||
copy(buf[len(head):], buf)
|
||||
copy(buf, head)
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
var ctxs = struct {
|
||||
sync.Mutex
|
||||
m map[*http.Request]*context
|
||||
bg *context // background context, lazily initialized
|
||||
// dec is used by tests to decorate the netcontext.Context returned
|
||||
// for a given request. This allows tests to add overrides (such as
|
||||
// WithAppIDOverride) to the context. The map is nil outside tests.
|
||||
dec map[*http.Request]func(netcontext.Context) netcontext.Context
|
||||
}{
|
||||
m: make(map[*http.Request]*context),
|
||||
}
|
||||
|
||||
// context represents the context of an in-flight HTTP request.
|
||||
// It implements the appengine.Context and http.ResponseWriter interfaces.
|
||||
type context struct {
|
||||
req *http.Request
|
||||
|
||||
outCode int
|
||||
outHeader http.Header
|
||||
outBody []byte
|
||||
|
||||
pendingLogs struct {
|
||||
sync.Mutex
|
||||
lines []*logpb.UserAppLogLine
|
||||
flushes int
|
||||
}
|
||||
|
||||
apiURL *url.URL
|
||||
}
|
||||
|
||||
var contextKey = "holds a *context"
|
||||
|
||||
// fromContext returns the App Engine context or nil if ctx is not
|
||||
// derived from an App Engine context.
|
||||
func fromContext(ctx netcontext.Context) *context {
|
||||
c, _ := ctx.Value(&contextKey).(*context)
|
||||
return c
|
||||
}
|
||||
|
||||
func withContext(parent netcontext.Context, c *context) netcontext.Context {
|
||||
ctx := netcontext.WithValue(parent, &contextKey, c)
|
||||
if ns := c.req.Header.Get(curNamespaceHeader); ns != "" {
|
||||
ctx = withNamespace(ctx, ns)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
func toContext(c *context) netcontext.Context {
|
||||
return withContext(netcontext.Background(), c)
|
||||
}
|
||||
|
||||
func IncomingHeaders(ctx netcontext.Context) http.Header {
|
||||
if c := fromContext(ctx); c != nil {
|
||||
return c.req.Header
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReqContext(req *http.Request) netcontext.Context {
|
||||
return WithContext(netcontext.Background(), req)
|
||||
}
|
||||
|
||||
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
|
||||
ctxs.Lock()
|
||||
c := ctxs.m[req]
|
||||
d := ctxs.dec[req]
|
||||
ctxs.Unlock()
|
||||
|
||||
if d != nil {
|
||||
parent = d(parent)
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
// Someone passed in an http.Request that is not in-flight.
|
||||
// We panic here rather than panicking at a later point
|
||||
// so that stack traces will be more sensible.
|
||||
log.Panic("appengine: NewContext passed an unknown http.Request")
|
||||
}
|
||||
return withContext(parent, c)
|
||||
}
|
||||
|
||||
// DefaultTicket returns a ticket used for background context or dev_appserver.
|
||||
func DefaultTicket() string {
|
||||
defaultTicketOnce.Do(func() {
|
||||
if IsDevAppServer() {
|
||||
defaultTicket = "testapp" + defaultTicketSuffix
|
||||
return
|
||||
}
|
||||
appID := partitionlessAppID()
|
||||
escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
|
||||
majVersion := VersionID(nil)
|
||||
if i := strings.Index(majVersion, "."); i > 0 {
|
||||
majVersion = majVersion[:i]
|
||||
}
|
||||
defaultTicket = fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID())
|
||||
})
|
||||
return defaultTicket
|
||||
}
|
||||
|
||||
func BackgroundContext() netcontext.Context {
|
||||
ctxs.Lock()
|
||||
defer ctxs.Unlock()
|
||||
|
||||
if ctxs.bg != nil {
|
||||
return toContext(ctxs.bg)
|
||||
}
|
||||
|
||||
// Compute background security ticket.
|
||||
ticket := DefaultTicket()
|
||||
|
||||
ctxs.bg = &context{
|
||||
req: &http.Request{
|
||||
Header: http.Header{
|
||||
ticketHeader: []string{ticket},
|
||||
},
|
||||
},
|
||||
apiURL: apiURL(),
|
||||
}
|
||||
|
||||
// TODO(dsymonds): Wire up the shutdown handler to do a final flush.
|
||||
go ctxs.bg.logFlusher(make(chan int))
|
||||
|
||||
return toContext(ctxs.bg)
|
||||
}
|
||||
|
||||
// RegisterTestRequest registers the HTTP request req for testing, such that
|
||||
// any API calls are sent to the provided URL. It returns a closure to delete
|
||||
// the registration.
|
||||
// It should only be used by aetest package.
|
||||
func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) (*http.Request, func()) {
|
||||
c := &context{
|
||||
req: req,
|
||||
apiURL: apiURL,
|
||||
}
|
||||
ctxs.Lock()
|
||||
defer ctxs.Unlock()
|
||||
if _, ok := ctxs.m[req]; ok {
|
||||
log.Panic("req already associated with context")
|
||||
}
|
||||
if _, ok := ctxs.dec[req]; ok {
|
||||
log.Panic("req already associated with context")
|
||||
}
|
||||
if ctxs.dec == nil {
|
||||
ctxs.dec = make(map[*http.Request]func(netcontext.Context) netcontext.Context)
|
||||
}
|
||||
ctxs.m[req] = c
|
||||
ctxs.dec[req] = decorate
|
||||
|
||||
return req, func() {
|
||||
ctxs.Lock()
|
||||
delete(ctxs.m, req)
|
||||
delete(ctxs.dec, req)
|
||||
ctxs.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
var errTimeout = &CallError{
|
||||
Detail: "Deadline exceeded",
|
||||
Code: int32(remotepb.RpcError_CANCELLED),
|
||||
Timeout: true,
|
||||
}
|
||||
|
||||
func (c *context) Header() http.Header { return c.outHeader }
|
||||
|
||||
// Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status
|
||||
// codes do not permit a response body (nor response entity headers such as
|
||||
// Content-Length, Content-Type, etc).
|
||||
func bodyAllowedForStatus(status int) bool {
|
||||
switch {
|
||||
case status >= 100 && status <= 199:
|
||||
return false
|
||||
case status == 204:
|
||||
return false
|
||||
case status == 304:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) Write(b []byte) (int, error) {
|
||||
if c.outCode == 0 {
|
||||
c.WriteHeader(http.StatusOK)
|
||||
}
|
||||
if len(b) > 0 && !bodyAllowedForStatus(c.outCode) {
|
||||
return 0, http.ErrBodyNotAllowed
|
||||
}
|
||||
c.outBody = append(c.outBody, b...)
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (c *context) WriteHeader(code int) {
|
||||
if c.outCode != 0 {
|
||||
logf(c, 3, "WriteHeader called multiple times on request.") // error level
|
||||
return
|
||||
}
|
||||
c.outCode = code
|
||||
}
|
||||
|
||||
func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) {
|
||||
hreq := &http.Request{
|
||||
Method: "POST",
|
||||
URL: c.apiURL,
|
||||
Header: http.Header{
|
||||
apiEndpointHeader: apiEndpointHeaderValue,
|
||||
apiMethodHeader: apiMethodHeaderValue,
|
||||
apiContentType: apiContentTypeValue,
|
||||
apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)},
|
||||
},
|
||||
Body: ioutil.NopCloser(bytes.NewReader(body)),
|
||||
ContentLength: int64(len(body)),
|
||||
Host: c.apiURL.Host,
|
||||
}
|
||||
if info := c.req.Header.Get(dapperHeader); info != "" {
|
||||
hreq.Header.Set(dapperHeader, info)
|
||||
}
|
||||
if info := c.req.Header.Get(traceHeader); info != "" {
|
||||
hreq.Header.Set(traceHeader, info)
|
||||
}
|
||||
|
||||
tr := apiHTTPClient.Transport.(*http.Transport)
|
||||
|
||||
var timedOut int32 // atomic; set to 1 if timed out
|
||||
t := time.AfterFunc(timeout, func() {
|
||||
atomic.StoreInt32(&timedOut, 1)
|
||||
tr.CancelRequest(hreq)
|
||||
})
|
||||
defer t.Stop()
|
||||
defer func() {
|
||||
// Check if timeout was exceeded.
|
||||
if atomic.LoadInt32(&timedOut) != 0 {
|
||||
err = errTimeout
|
||||
}
|
||||
}()
|
||||
|
||||
hresp, err := apiHTTPClient.Do(hreq)
|
||||
if err != nil {
|
||||
return nil, &CallError{
|
||||
Detail: fmt.Sprintf("service bridge HTTP failed: %v", err),
|
||||
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||
}
|
||||
}
|
||||
defer hresp.Body.Close()
|
||||
hrespBody, err := ioutil.ReadAll(hresp.Body)
|
||||
if hresp.StatusCode != 200 {
|
||||
return nil, &CallError{
|
||||
Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody),
|
||||
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, &CallError{
|
||||
Detail: fmt.Sprintf("service bridge response bad: %v", err),
|
||||
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||
}
|
||||
}
|
||||
return hrespBody, nil
|
||||
}
|
||||
|
||||
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
|
||||
if ns := NamespaceFromContext(ctx); ns != "" {
|
||||
if fn, ok := NamespaceMods[service]; ok {
|
||||
fn(in, ns)
|
||||
}
|
||||
}
|
||||
|
||||
if f, ctx, ok := callOverrideFromContext(ctx); ok {
|
||||
return f(ctx, service, method, in, out)
|
||||
}
|
||||
|
||||
// Handle already-done contexts quickly.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
c := fromContext(ctx)
|
||||
if c == nil {
|
||||
// Give a good error message rather than a panic lower down.
|
||||
return errNotAppEngineContext
|
||||
}
|
||||
|
||||
// Apply transaction modifications if we're in a transaction.
|
||||
if t := transactionFromContext(ctx); t != nil {
|
||||
if t.finished {
|
||||
return errors.New("transaction context has expired")
|
||||
}
|
||||
applyTransaction(in, &t.transaction)
|
||||
}
|
||||
|
||||
// Default RPC timeout is 60s.
|
||||
timeout := 60 * time.Second
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
timeout = deadline.Sub(time.Now())
|
||||
}
|
||||
|
||||
data, err := proto.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ticket := c.req.Header.Get(ticketHeader)
|
||||
// Use a test ticket under test environment.
|
||||
if ticket == "" {
|
||||
if appid := ctx.Value(&appIDOverrideKey); appid != nil {
|
||||
ticket = appid.(string) + defaultTicketSuffix
|
||||
}
|
||||
}
|
||||
// Fall back to use background ticket when the request ticket is not available in Flex or dev_appserver.
|
||||
if ticket == "" {
|
||||
ticket = DefaultTicket()
|
||||
}
|
||||
req := &remotepb.Request{
|
||||
ServiceName: &service,
|
||||
Method: &method,
|
||||
Request: data,
|
||||
RequestId: &ticket,
|
||||
}
|
||||
hreqBody, err := proto.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hrespBody, err := c.post(hreqBody, timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := &remotepb.Response{}
|
||||
if err := proto.Unmarshal(hrespBody, res); err != nil {
|
||||
return err
|
||||
}
|
||||
if res.RpcError != nil {
|
||||
ce := &CallError{
|
||||
Detail: res.RpcError.GetDetail(),
|
||||
Code: *res.RpcError.Code,
|
||||
}
|
||||
switch remotepb.RpcError_ErrorCode(ce.Code) {
|
||||
case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED:
|
||||
ce.Timeout = true
|
||||
}
|
||||
return ce
|
||||
}
|
||||
if res.ApplicationError != nil {
|
||||
return &APIError{
|
||||
Service: *req.ServiceName,
|
||||
Detail: res.ApplicationError.GetDetail(),
|
||||
Code: *res.ApplicationError.Code,
|
||||
}
|
||||
}
|
||||
if res.Exception != nil || res.JavaException != nil {
|
||||
// This shouldn't happen, but let's be defensive.
|
||||
return &CallError{
|
||||
Detail: "service bridge returned exception",
|
||||
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||
}
|
||||
}
|
||||
return proto.Unmarshal(res.Response, out)
|
||||
}
|
||||
|
||||
func (c *context) Request() *http.Request {
|
||||
return c.req
|
||||
}
|
||||
|
||||
func (c *context) addLogLine(ll *logpb.UserAppLogLine) {
|
||||
// Truncate long log lines.
|
||||
// TODO(dsymonds): Check if this is still necessary.
|
||||
const lim = 8 << 10
|
||||
if len(*ll.Message) > lim {
|
||||
suffix := fmt.Sprintf("...(length %d)", len(*ll.Message))
|
||||
ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix)
|
||||
}
|
||||
|
||||
c.pendingLogs.Lock()
|
||||
c.pendingLogs.lines = append(c.pendingLogs.lines, ll)
|
||||
c.pendingLogs.Unlock()
|
||||
}
|
||||
|
||||
var logLevelName = map[int64]string{
|
||||
0: "DEBUG",
|
||||
1: "INFO",
|
||||
2: "WARNING",
|
||||
3: "ERROR",
|
||||
4: "CRITICAL",
|
||||
}
|
||||
|
||||
func logf(c *context, level int64, format string, args ...interface{}) {
|
||||
if c == nil {
|
||||
panic("not an App Engine context")
|
||||
}
|
||||
s := fmt.Sprintf(format, args...)
|
||||
s = strings.TrimRight(s, "\n") // Remove any trailing newline characters.
|
||||
c.addLogLine(&logpb.UserAppLogLine{
|
||||
TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3),
|
||||
Level: &level,
|
||||
Message: &s,
|
||||
})
|
||||
log.Print(logLevelName[level] + ": " + s)
|
||||
}
|
||||
|
||||
// flushLog attempts to flush any pending logs to the appserver.
|
||||
// It should not be called concurrently.
|
||||
func (c *context) flushLog(force bool) (flushed bool) {
|
||||
c.pendingLogs.Lock()
|
||||
// Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious.
|
||||
n, rem := 0, 30<<20
|
||||
for ; n < len(c.pendingLogs.lines); n++ {
|
||||
ll := c.pendingLogs.lines[n]
|
||||
// Each log line will require about 3 bytes of overhead.
|
||||
nb := proto.Size(ll) + 3
|
||||
if nb > rem {
|
||||
break
|
||||
}
|
||||
rem -= nb
|
||||
}
|
||||
lines := c.pendingLogs.lines[:n]
|
||||
c.pendingLogs.lines = c.pendingLogs.lines[n:]
|
||||
c.pendingLogs.Unlock()
|
||||
|
||||
if len(lines) == 0 && !force {
|
||||
// Nothing to flush.
|
||||
return false
|
||||
}
|
||||
|
||||
rescueLogs := false
|
||||
defer func() {
|
||||
if rescueLogs {
|
||||
c.pendingLogs.Lock()
|
||||
c.pendingLogs.lines = append(lines, c.pendingLogs.lines...)
|
||||
c.pendingLogs.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
buf, err := proto.Marshal(&logpb.UserAppLogGroup{
|
||||
LogLine: lines,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err)
|
||||
rescueLogs = true
|
||||
return false
|
||||
}
|
||||
|
||||
req := &logpb.FlushRequest{
|
||||
Logs: buf,
|
||||
}
|
||||
res := &basepb.VoidProto{}
|
||||
c.pendingLogs.Lock()
|
||||
c.pendingLogs.flushes++
|
||||
c.pendingLogs.Unlock()
|
||||
if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil {
|
||||
log.Printf("internal.flushLog: Flush RPC: %v", err)
|
||||
rescueLogs = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
// Log flushing parameters.
|
||||
flushInterval = 1 * time.Second
|
||||
forceFlushInterval = 60 * time.Second
|
||||
)
|
||||
|
||||
func (c *context) logFlusher(stop <-chan int) {
|
||||
lastFlush := time.Now()
|
||||
tick := time.NewTicker(flushInterval)
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
// Request finished.
|
||||
tick.Stop()
|
||||
return
|
||||
case <-tick.C:
|
||||
force := time.Now().Sub(lastFlush) > forceFlushInterval
|
||||
if c.flushLog(force) {
|
||||
lastFlush = time.Now()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ContextForTesting(req *http.Request) netcontext.Context {
|
||||
return toContext(&context{req: req})
|
||||
}
|
||||
41
vendor/google.golang.org/appengine/internal/identity.go
generated
vendored
41
vendor/google.golang.org/appengine/internal/identity.go
generated
vendored
|
|
@ -4,11 +4,46 @@
|
|||
|
||||
package internal
|
||||
|
||||
import netcontext "golang.org/x/net/context"
|
||||
import (
|
||||
"os"
|
||||
|
||||
// These functions are implementations of the wrapper functions
|
||||
// in ../appengine/identity.go. See that file for commentary.
|
||||
netcontext "golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
// This is set to true in identity_classic.go, which is behind the appengine build tag.
|
||||
// The appengine build tag is set for the first generation runtimes (<= Go 1.9) but not
|
||||
// the second generation runtimes (>= Go 1.11), so this indicates whether we're on a
|
||||
// first-gen runtime. See IsStandard below for the second-gen check.
|
||||
appengineStandard bool
|
||||
|
||||
// This is set to true in identity_flex.go, which is behind the appenginevm build tag.
|
||||
appengineFlex bool
|
||||
)
|
||||
|
||||
// AppID is the implementation of the wrapper function of the same name in
|
||||
// ../identity.go. See that file for commentary.
|
||||
func AppID(c netcontext.Context) string {
|
||||
return appID(FullyQualifiedAppID(c))
|
||||
}
|
||||
|
||||
// IsStandard is the implementation of the wrapper function of the same name in
|
||||
// ../appengine.go. See that file for commentary.
|
||||
func IsStandard() bool {
|
||||
// appengineStandard will be true for first-gen runtimes (<= Go 1.9) but not
|
||||
// second-gen (>= Go 1.11). Second-gen runtimes set $GAE_ENV so we use that
|
||||
// to check if we're on a second-gen runtime.
|
||||
return appengineStandard || os.Getenv("GAE_ENV") == "standard"
|
||||
}
|
||||
|
||||
// IsFlex is the implementation of the wrapper function of the same name in
|
||||
// ../appengine.go. See that file for commentary.
|
||||
func IsFlex() bool {
|
||||
return appengineFlex
|
||||
}
|
||||
|
||||
// IsAppEngine is the implementation of the wrapper function of the same name in
|
||||
// ../appengine.go. See that file for commentary.
|
||||
func IsAppEngine() bool {
|
||||
return IsStandard() || IsFlex()
|
||||
}
|
||||
|
|
|
|||
4
vendor/google.golang.org/appengine/internal/identity_classic.go
generated
vendored
4
vendor/google.golang.org/appengine/internal/identity_classic.go
generated
vendored
|
|
@ -12,6 +12,10 @@ import (
|
|||
netcontext "golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func init() {
|
||||
appengineStandard = true
|
||||
}
|
||||
|
||||
func DefaultVersionHostname(ctx netcontext.Context) string {
|
||||
c := fromContext(ctx)
|
||||
if c == nil {
|
||||
|
|
|
|||
11
vendor/google.golang.org/appengine/internal/identity_flex.go
generated
vendored
Normal file
11
vendor/google.golang.org/appengine/internal/identity_flex.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2018 Google LLC. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appenginevm
|
||||
|
||||
package internal
|
||||
|
||||
func init() {
|
||||
appengineFlex = true
|
||||
}
|
||||
18
vendor/google.golang.org/appengine/travis_install.sh
generated
vendored
Executable file
18
vendor/google.golang.org/appengine/travis_install.sh
generated
vendored
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ $GO111MODULE == "on" ]]; then
|
||||
go get .
|
||||
else
|
||||
go get -u -v $(go list -f '{{join .Imports "\n"}}{{"\n"}}{{join .TestImports "\n"}}' ./... | sort | uniq | grep -v appengine)
|
||||
fi
|
||||
|
||||
if [[ $GOAPP == "true" ]]; then
|
||||
mkdir /tmp/sdk
|
||||
curl -o /tmp/sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip"
|
||||
unzip -q /tmp/sdk.zip -d /tmp/sdk
|
||||
# NOTE: Set the following env vars in the test script:
|
||||
# export PATH="$PATH:/tmp/sdk/go_appengine"
|
||||
# export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
|
||||
fi
|
||||
|
||||
12
vendor/google.golang.org/appengine/travis_test.sh
generated
vendored
Executable file
12
vendor/google.golang.org/appengine/travis_test.sh
generated
vendored
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
go version
|
||||
go test -v google.golang.org/appengine/...
|
||||
go test -v -race google.golang.org/appengine/...
|
||||
if [[ $GOAPP == "true" ]]; then
|
||||
export PATH="$PATH:/tmp/sdk/go_appengine"
|
||||
export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
|
||||
goapp version
|
||||
goapp test -v google.golang.org/appengine/...
|
||||
fi
|
||||
6
vendor/google.golang.org/genproto/.travis.yml
generated
vendored
6
vendor/google.golang.org/genproto/.travis.yml
generated
vendored
|
|
@ -1,8 +1,8 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
go_import_path: google.golang.org/genproto
|
||||
|
||||
script:
|
||||
|
|
|
|||
7
vendor/google.golang.org/genproto/go.mod
generated
vendored
Normal file
7
vendor/google.golang.org/genproto/go.mod
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module google.golang.org/genproto
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.2.0
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953
|
||||
google.golang.org/grpc v1.16.0
|
||||
)
|
||||
26
vendor/google.golang.org/genproto/go.sum
generated
vendored
Normal file
26
vendor/google.golang.org/genproto/go.sum
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953 h1:LuZIitY8waaxUfNIdtajyE/YzA/zyf0YxXG27VpLrkg=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
3
vendor/google.golang.org/grpc/.travis.yml
generated
vendored
3
vendor/google.golang.org/grpc/.travis.yml
generated
vendored
|
|
@ -26,7 +26,8 @@ before_install:
|
|||
- if [[ "${TRAVIS_EVENT_TYPE}" != "cron" ]]; then VET_SKIP_PROTO=1; fi
|
||||
|
||||
install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi
|
||||
- try3() { eval "$*" || eval "$*" || eval "$*"; }
|
||||
- try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi'
|
||||
- if [[ "${GAE}" = 1 ]]; then source ./install_gae.sh; make testappenginedeps; fi
|
||||
- if [[ "${VET}" = 1 ]]; then ./vet.sh -install; fi
|
||||
|
||||
|
|
|
|||
4
vendor/google.golang.org/grpc/Makefile
generated
vendored
4
vendor/google.golang.org/grpc/Makefile
generated
vendored
|
|
@ -17,10 +17,10 @@ proto:
|
|||
go generate google.golang.org/grpc/...
|
||||
|
||||
test: testdeps
|
||||
go test -cpu 1,4 -timeout 5m google.golang.org/grpc/...
|
||||
go test -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
||||
|
||||
testappengine: testappenginedeps
|
||||
goapp test -cpu 1,4 -timeout 5m google.golang.org/grpc/...
|
||||
goapp test -cpu 1,4 -timeout 7m google.golang.org/grpc/...
|
||||
|
||||
testappenginedeps:
|
||||
goapp get -d -v -t -tags 'appengine appenginevm' google.golang.org/grpc/...
|
||||
|
|
|
|||
22
vendor/google.golang.org/grpc/README.md
generated
vendored
22
vendor/google.golang.org/grpc/README.md
generated
vendored
|
|
@ -43,3 +43,25 @@ Please update proto package, gRPC package and rebuild the proto files:
|
|||
- `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}`
|
||||
- `go get -u google.golang.org/grpc`
|
||||
- `protoc --go_out=plugins=grpc:. *.proto`
|
||||
|
||||
#### How to turn on logging
|
||||
|
||||
The default logger is controlled by the environment variables. Turn everything
|
||||
on by setting:
|
||||
|
||||
```
|
||||
GRPC_GO_LOG_VERBOSITY_LEVEL=99 GRPC_GO_LOG_SEVERITY_LEVEL=info
|
||||
```
|
||||
|
||||
#### The RPC failed with error `"code = Unavailable desc = transport is closing"`
|
||||
|
||||
This error means the connection the RPC is using was closed, and there are many
|
||||
possible reasons, including:
|
||||
1. mis-configured transport credentials, connection failed on handshaking
|
||||
1. bytes disrupted, possibly by a proxy in between
|
||||
1. server shutdown
|
||||
|
||||
It can be tricky to debug this because the error happens on the client side but
|
||||
the root cause of the connection being closed is on the server side. Turn on
|
||||
logging on __both client and server__, and see if there are any transport
|
||||
errors.
|
||||
|
|
|
|||
15
vendor/google.golang.org/grpc/balancer/balancer.go
generated
vendored
15
vendor/google.golang.org/grpc/balancer/balancer.go
generated
vendored
|
|
@ -28,6 +28,7 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
|
|
@ -88,7 +89,12 @@ type SubConn interface {
|
|||
}
|
||||
|
||||
// NewSubConnOptions contains options to create new SubConn.
|
||||
type NewSubConnOptions struct{}
|
||||
type NewSubConnOptions struct {
|
||||
// CredsBundle is the credentials bundle that will be used in the created
|
||||
// SubConn. If it's nil, the original creds from grpc DialOptions will be
|
||||
// used.
|
||||
CredsBundle credentials.Bundle
|
||||
}
|
||||
|
||||
// ClientConn represents a gRPC ClientConn.
|
||||
//
|
||||
|
|
@ -125,6 +131,8 @@ type BuildOptions struct {
|
|||
// use to dial to a remote load balancer server. The Balancer implementations
|
||||
// can ignore this if it does not need to talk to another party securely.
|
||||
DialCreds credentials.TransportCredentials
|
||||
// CredsBundle is the credentials bundle that the Balancer can use.
|
||||
CredsBundle credentials.Bundle
|
||||
// Dialer is the custom dialer the Balancer implementation can use to dial
|
||||
// to a remote load balancer server. The Balancer implementations
|
||||
// can ignore this if it doesn't need to talk to remote balancer.
|
||||
|
|
@ -147,12 +155,17 @@ type PickOptions struct {
|
|||
// FullMethodName is the method name that NewClientStream() is called
|
||||
// with. The canonical format is /service/Method.
|
||||
FullMethodName string
|
||||
// Header contains the metadata from the RPC's client header. The metadata
|
||||
// should not be modified; make a copy first if needed.
|
||||
Header metadata.MD
|
||||
}
|
||||
|
||||
// DoneInfo contains additional information for done.
|
||||
type DoneInfo struct {
|
||||
// Err is the rpc error the RPC finished with. It could be nil.
|
||||
Err error
|
||||
// Trailer contains the metadata from the RPC's trailer, if present.
|
||||
Trailer metadata.MD
|
||||
// BytesSent indicates if any bytes have been sent to the server.
|
||||
BytesSent bool
|
||||
// BytesReceived indicates if any byte has been received from the server.
|
||||
|
|
|
|||
5
vendor/google.golang.org/grpc/balancer_conn_wrappers.go
generated
vendored
5
vendor/google.golang.org/grpc/balancer_conn_wrappers.go
generated
vendored
|
|
@ -197,7 +197,7 @@ func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer
|
|||
if ccb.subConns == nil {
|
||||
return nil, fmt.Errorf("grpc: ClientConn balancer wrapper was closed")
|
||||
}
|
||||
ac, err := ccb.cc.newAddrConn(addrs)
|
||||
ac, err := ccb.cc.newAddrConn(addrs, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -257,6 +257,7 @@ func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) {
|
|||
}
|
||||
if !acbw.ac.tryUpdateAddrs(addrs) {
|
||||
cc := acbw.ac.cc
|
||||
opts := acbw.ac.scopts
|
||||
acbw.ac.mu.Lock()
|
||||
// Set old ac.acbw to nil so the Shutdown state update will be ignored
|
||||
// by balancer.
|
||||
|
|
@ -272,7 +273,7 @@ func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) {
|
|||
return
|
||||
}
|
||||
|
||||
ac, err := cc.newAddrConn(addrs)
|
||||
ac, err := cc.newAddrConn(addrs, opts)
|
||||
if err != nil {
|
||||
grpclog.Warningf("acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", err)
|
||||
return
|
||||
|
|
|
|||
701
vendor/google.golang.org/grpc/clientconn.go
generated
vendored
701
vendor/google.golang.org/grpc/clientconn.go
generated
vendored
|
|
@ -30,7 +30,6 @@ import (
|
|||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/trace"
|
||||
"google.golang.org/grpc/balancer"
|
||||
_ "google.golang.org/grpc/balancer/roundrobin" // To register roundrobin.
|
||||
"google.golang.org/grpc/codes"
|
||||
|
|
@ -41,6 +40,7 @@ import (
|
|||
"google.golang.org/grpc/internal/channelz"
|
||||
"google.golang.org/grpc/internal/transport"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/resolver"
|
||||
_ "google.golang.org/grpc/resolver/dns" // To register dns resolver.
|
||||
_ "google.golang.org/grpc/resolver/passthrough" // To register passthrough resolver.
|
||||
|
|
@ -80,6 +80,9 @@ var (
|
|||
// being set for ClientConn. Users should either set one or explicitly
|
||||
// call WithInsecure DialOption to disable security.
|
||||
errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)")
|
||||
// errTransportCredsAndBundle indicates that creds bundle is used together
|
||||
// with other individual Transport Credentials.
|
||||
errTransportCredsAndBundle = errors.New("grpc: credentials.Bundle may not be used with individual TransportCredentials")
|
||||
// errTransportCredentialsMissing indicates that users want to transmit security
|
||||
// information (e.g., oauth2 token) which requires secure connection on an insecure
|
||||
// connection.
|
||||
|
|
@ -137,17 +140,33 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
|
|||
if channelz.IsOn() {
|
||||
if cc.dopts.channelzParentID != 0 {
|
||||
cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, cc.dopts.channelzParentID, target)
|
||||
channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: "Channel Created",
|
||||
Severity: channelz.CtINFO,
|
||||
Parent: &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Nested Channel(id:%d) created", cc.channelzID),
|
||||
Severity: channelz.CtINFO,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, 0, target)
|
||||
channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: "Channel Created",
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
cc.csMgr.channelzID = cc.channelzID
|
||||
}
|
||||
|
||||
if !cc.dopts.insecure {
|
||||
if cc.dopts.copts.TransportCredentials == nil {
|
||||
if cc.dopts.copts.TransportCredentials == nil && cc.dopts.copts.CredsBundle == nil {
|
||||
return nil, errNoTransportSecurity
|
||||
}
|
||||
if cc.dopts.copts.TransportCredentials != nil && cc.dopts.copts.CredsBundle != nil {
|
||||
return nil, errTransportCredsAndBundle
|
||||
}
|
||||
} else {
|
||||
if cc.dopts.copts.TransportCredentials != nil {
|
||||
if cc.dopts.copts.TransportCredentials != nil || cc.dopts.copts.CredsBundle != nil {
|
||||
return nil, errCredentialsConflict
|
||||
}
|
||||
for _, cd := range cc.dopts.copts.PerRPCCredentials {
|
||||
|
|
@ -260,6 +279,7 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
|
|||
}
|
||||
cc.balancerBuildOpts = balancer.BuildOptions{
|
||||
DialCreds: credsClone,
|
||||
CredsBundle: cc.dopts.copts.CredsBundle,
|
||||
Dialer: cc.dopts.copts.Dialer,
|
||||
ChannelzParentID: cc.channelzID,
|
||||
}
|
||||
|
|
@ -308,6 +328,7 @@ type connectivityStateManager struct {
|
|||
mu sync.Mutex
|
||||
state connectivity.State
|
||||
notifyChan chan struct{}
|
||||
channelzID int64
|
||||
}
|
||||
|
||||
// updateState updates the connectivity.State of ClientConn.
|
||||
|
|
@ -323,6 +344,12 @@ func (csm *connectivityStateManager) updateState(state connectivity.State) {
|
|||
return
|
||||
}
|
||||
csm.state = state
|
||||
if channelz.IsOn() {
|
||||
channelz.AddTraceEvent(csm.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Channel Connectivity change to %v", state),
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
if csm.notifyChan != nil {
|
||||
// There are other goroutines waiting on this channel.
|
||||
close(csm.notifyChan)
|
||||
|
|
@ -500,10 +527,26 @@ func (cc *ClientConn) switchBalancer(name string) {
|
|||
}
|
||||
|
||||
builder := balancer.Get(name)
|
||||
// TODO(yuxuanli): If user send a service config that does not contain a valid balancer name, should
|
||||
// we reuse previous one?
|
||||
if channelz.IsOn() {
|
||||
if builder == nil {
|
||||
channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Channel switches to new LB policy %q due to fallback from invalid balancer name", PickFirstBalancerName),
|
||||
Severity: channelz.CtWarning,
|
||||
})
|
||||
} else {
|
||||
channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Channel switches to new LB policy %q", name),
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
}
|
||||
if builder == nil {
|
||||
grpclog.Infof("failed to get balancer builder for: %v, using pick_first instead", name)
|
||||
builder = newPickfirstBuilder()
|
||||
}
|
||||
|
||||
cc.preBalancerName = cc.curBalancerName
|
||||
cc.curBalancerName = builder.Name()
|
||||
cc.balancerWrapper = newCCBalancerWrapper(cc, builder, cc.balancerBuildOpts)
|
||||
|
|
@ -524,13 +567,15 @@ func (cc *ClientConn) handleSubConnStateChange(sc balancer.SubConn, s connectivi
|
|||
// newAddrConn creates an addrConn for addrs and adds it to cc.conns.
|
||||
//
|
||||
// Caller needs to make sure len(addrs) > 0.
|
||||
func (cc *ClientConn) newAddrConn(addrs []resolver.Address) (*addrConn, error) {
|
||||
func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (*addrConn, error) {
|
||||
ac := &addrConn{
|
||||
cc: cc,
|
||||
addrs: addrs,
|
||||
dopts: cc.dopts,
|
||||
czData: new(channelzData),
|
||||
resetBackoff: make(chan struct{}),
|
||||
cc: cc,
|
||||
addrs: addrs,
|
||||
scopts: opts,
|
||||
dopts: cc.dopts,
|
||||
czData: new(channelzData),
|
||||
successfulHandshake: true, // make the first nextAddr() call _not_ move addrIdx up by 1
|
||||
resetBackoff: make(chan struct{}),
|
||||
}
|
||||
ac.ctx, ac.cancel = context.WithCancel(cc.ctx)
|
||||
// Track ac in cc. This needs to be done before any getTransport(...) is called.
|
||||
|
|
@ -541,6 +586,14 @@ func (cc *ClientConn) newAddrConn(addrs []resolver.Address) (*addrConn, error) {
|
|||
}
|
||||
if channelz.IsOn() {
|
||||
ac.channelzID = channelz.RegisterSubChannel(ac, cc.channelzID, "")
|
||||
channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: "Subchannel Created",
|
||||
Severity: channelz.CtINFO,
|
||||
Parent: &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Subchannel(id:%d) created", ac.channelzID),
|
||||
Severity: channelz.CtINFO,
|
||||
},
|
||||
})
|
||||
}
|
||||
cc.conns[ac] = struct{}{}
|
||||
cc.mu.Unlock()
|
||||
|
|
@ -590,11 +643,9 @@ func (cc *ClientConn) incrCallsFailed() {
|
|||
atomic.AddInt64(&cc.czData.callsFailed, 1)
|
||||
}
|
||||
|
||||
// connect starts to creating transport and also starts the transport monitor
|
||||
// goroutine for this ac.
|
||||
// connect starts creating a transport.
|
||||
// It does nothing if the ac is not IDLE.
|
||||
// TODO(bar) Move this to the addrConn section.
|
||||
// This was part of resetAddrConn, keep it here to make the diff look clean.
|
||||
func (ac *addrConn) connect() error {
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
|
|
@ -605,22 +656,12 @@ func (ac *addrConn) connect() error {
|
|||
ac.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
ac.state = connectivity.Connecting
|
||||
ac.updateConnectivityState(connectivity.Connecting)
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
ac.mu.Unlock()
|
||||
|
||||
// Start a goroutine connecting to the server asynchronously.
|
||||
go func() {
|
||||
if err := ac.resetTransport(); err != nil {
|
||||
grpclog.Warningf("Failed to dial %s: %v; please retry.", ac.addrs[0].Addr, err)
|
||||
if err != errConnClosing {
|
||||
// Keep this ac in cc.conns, to get the reason it's torn down.
|
||||
ac.tearDown(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
ac.transportMonitor()
|
||||
}()
|
||||
go ac.resetTransport(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -649,7 +690,7 @@ func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool {
|
|||
grpclog.Infof("addrConn: tryUpdateAddrs curAddrFound: %v", curAddrFound)
|
||||
if curAddrFound {
|
||||
ac.addrs = addrs
|
||||
ac.reconnectIdx = 0 // Start reconnecting from beginning in the new list.
|
||||
ac.addrIdx = 0 // Start reconnecting from beginning in the new list.
|
||||
}
|
||||
|
||||
return curAddrFound
|
||||
|
|
@ -675,8 +716,10 @@ func (cc *ClientConn) GetMethodConfig(method string) MethodConfig {
|
|||
}
|
||||
|
||||
func (cc *ClientConn) getTransport(ctx context.Context, failfast bool, method string) (transport.ClientTransport, func(balancer.DoneInfo), error) {
|
||||
hdr, _ := metadata.FromOutgoingContext(ctx)
|
||||
t, done, err := cc.blockingpicker.pick(ctx, failfast, balancer.PickOptions{
|
||||
FullMethodName: method,
|
||||
Header: hdr,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, toRPCErr(err)
|
||||
|
|
@ -690,11 +733,29 @@ func (cc *ClientConn) handleServiceConfig(js string) error {
|
|||
if cc.dopts.disableServiceConfig {
|
||||
return nil
|
||||
}
|
||||
if cc.scRaw == js {
|
||||
return nil
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{
|
||||
// The special formatting of \"%s\" instead of %q is to provide nice printing of service config
|
||||
// for human consumption.
|
||||
Desc: fmt.Sprintf("Channel has a new service config \"%s\"", js),
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
sc, err := parseServiceConfig(js)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cc.mu.Lock()
|
||||
// Check if the ClientConn is already closed. Some fields (e.g.
|
||||
// balancerWrapper) are set to nil when closing the ClientConn, and could
|
||||
// cause nil pointer panic if we don't have this check.
|
||||
if cc.conns == nil {
|
||||
cc.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
cc.scRaw = js
|
||||
cc.sc = sc
|
||||
|
||||
|
|
@ -788,6 +849,19 @@ func (cc *ClientConn) Close() error {
|
|||
ac.tearDown(ErrClientConnClosing)
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
ted := &channelz.TraceEventDesc{
|
||||
Desc: "Channel Deleted",
|
||||
Severity: channelz.CtINFO,
|
||||
}
|
||||
if cc.dopts.channelzParentID != 0 {
|
||||
ted.Parent = &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Nested channel(id:%d) deleted", cc.channelzID),
|
||||
Severity: channelz.CtINFO,
|
||||
}
|
||||
}
|
||||
channelz.AddTraceEvent(cc.channelzID, ted)
|
||||
// TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to
|
||||
// the entity beng deleted, and thus prevent it from being deleted right away.
|
||||
channelz.RemoveEntry(cc.channelzID)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -799,26 +873,25 @@ type addrConn struct {
|
|||
cancel context.CancelFunc
|
||||
|
||||
cc *ClientConn
|
||||
addrs []resolver.Address
|
||||
dopts dialOptions
|
||||
events trace.EventLog
|
||||
acbw balancer.SubConn
|
||||
scopts balancer.NewSubConnOptions
|
||||
|
||||
mu sync.Mutex
|
||||
curAddr resolver.Address
|
||||
reconnectIdx int // The index in addrs list to start reconnecting from.
|
||||
state connectivity.State
|
||||
// ready is closed and becomes nil when a new transport is up or failed
|
||||
// due to timeout.
|
||||
ready chan struct{}
|
||||
transport transport.ClientTransport
|
||||
transport transport.ClientTransport // The current transport.
|
||||
|
||||
// The reason this addrConn is torn down.
|
||||
tearDownErr error
|
||||
mu sync.Mutex
|
||||
addrIdx int // The index in addrs list to start reconnecting from.
|
||||
curAddr resolver.Address // The current address.
|
||||
addrs []resolver.Address // All addresses that the resolver resolved to.
|
||||
|
||||
connectRetryNum int
|
||||
// Use updateConnectivityState for updating addrConn's connectivity state.
|
||||
state connectivity.State
|
||||
|
||||
tearDownErr error // The reason this addrConn is torn down.
|
||||
|
||||
backoffIdx int
|
||||
// backoffDeadline is the time until which resetTransport needs to
|
||||
// wait before increasing connectRetryNum count.
|
||||
// wait before increasing backoffIdx count.
|
||||
backoffDeadline time.Time
|
||||
// connectDeadline is the time by which all connection
|
||||
// negotiations must complete.
|
||||
|
|
@ -828,6 +901,19 @@ type addrConn struct {
|
|||
|
||||
channelzID int64 // channelz unique identification number
|
||||
czData *channelzData
|
||||
|
||||
successfulHandshake bool
|
||||
}
|
||||
|
||||
// Note: this requires a lock on ac.mu.
|
||||
func (ac *addrConn) updateConnectivityState(s connectivity.State) {
|
||||
ac.state = s
|
||||
if channelz.IsOn() {
|
||||
channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Subchannel Connectivity change to %v", s),
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// adjustParams updates parameters used to create transports upon
|
||||
|
|
@ -844,301 +930,328 @@ func (ac *addrConn) adjustParams(r transport.GoAwayReason) {
|
|||
}
|
||||
}
|
||||
|
||||
// printf records an event in ac's event log, unless ac has been closed.
|
||||
// REQUIRES ac.mu is held.
|
||||
func (ac *addrConn) printf(format string, a ...interface{}) {
|
||||
if ac.events != nil {
|
||||
ac.events.Printf(format, a...)
|
||||
}
|
||||
}
|
||||
|
||||
// resetTransport recreates a transport to the address for ac. The old
|
||||
// transport will close itself on error or when the clientconn is closed.
|
||||
// The created transport must receive initial settings frame from the server.
|
||||
// In case that doesn't happen, transportMonitor will kill the newly created
|
||||
// transport after connectDeadline has expired.
|
||||
// In case there was an error on the transport before the settings frame was
|
||||
// received, resetTransport resumes connecting to backends after the one that
|
||||
// was previously connected to. In case end of the list is reached, resetTransport
|
||||
// backs off until the original deadline.
|
||||
// If the DialOption WithWaitForHandshake was set, resetTrasport returns
|
||||
// successfully only after server settings are received.
|
||||
// resetTransport makes sure that a healthy ac.transport exists.
|
||||
//
|
||||
// TODO(bar) make sure all state transitions are valid.
|
||||
func (ac *addrConn) resetTransport() error {
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return errConnClosing
|
||||
}
|
||||
if ac.ready != nil {
|
||||
close(ac.ready)
|
||||
ac.ready = nil
|
||||
}
|
||||
ac.transport = nil
|
||||
ridx := ac.reconnectIdx
|
||||
ac.mu.Unlock()
|
||||
ac.cc.mu.RLock()
|
||||
ac.dopts.copts.KeepaliveParams = ac.cc.mkp
|
||||
ac.cc.mu.RUnlock()
|
||||
var backoffDeadline, connectDeadline time.Time
|
||||
var resetBackoff chan struct{}
|
||||
for connectRetryNum := 0; ; connectRetryNum++ {
|
||||
ac.mu.Lock()
|
||||
if ac.backoffDeadline.IsZero() {
|
||||
// This means either a successful HTTP2 connection was established
|
||||
// or this is the first time this addrConn is trying to establish a
|
||||
// connection.
|
||||
backoffFor := ac.dopts.bs.Backoff(connectRetryNum) // time.Duration.
|
||||
resetBackoff = ac.resetBackoff
|
||||
// This will be the duration that dial gets to finish.
|
||||
dialDuration := getMinConnectTimeout()
|
||||
if backoffFor > dialDuration {
|
||||
// Give dial more time as we keep failing to connect.
|
||||
dialDuration = backoffFor
|
||||
}
|
||||
start := time.Now()
|
||||
backoffDeadline = start.Add(backoffFor)
|
||||
connectDeadline = start.Add(dialDuration)
|
||||
ridx = 0 // Start connecting from the beginning.
|
||||
} else {
|
||||
// Continue trying to connect with the same deadlines.
|
||||
connectRetryNum = ac.connectRetryNum
|
||||
backoffDeadline = ac.backoffDeadline
|
||||
connectDeadline = ac.connectDeadline
|
||||
ac.backoffDeadline = time.Time{}
|
||||
ac.connectDeadline = time.Time{}
|
||||
ac.connectRetryNum = 0
|
||||
// The transport will close itself when it encounters an error, or on GOAWAY, or on deadline waiting for handshake, or
|
||||
// when the clientconn is closed. Each iteration creating a new transport will try a different address that the balancer
|
||||
// assigned to the addrConn, until it has tried all addresses. Once it has tried all addresses, it will re-resolve to
|
||||
// get a new address list. If an error is received, the list is re-resolved and the next reset attempt will try from the
|
||||
// beginning. This method has backoff built in. The backoff amount starts at 0 and increases each time resolution occurs
|
||||
// (addresses are exhausted). The backoff amount is reset to 0 each time a handshake is received.
|
||||
//
|
||||
// If the DialOption WithWaitForHandshake was set, resetTransport returns successfully only after handshake is received.
|
||||
func (ac *addrConn) resetTransport(resolveNow bool) {
|
||||
for {
|
||||
// If this is the first in a line of resets, we want to resolve immediately. The only other time we
|
||||
// want to reset is if we have tried all the addresses handed to us.
|
||||
if resolveNow {
|
||||
ac.mu.Lock()
|
||||
ac.cc.resolveNow(resolver.ResolveNowOption{})
|
||||
ac.mu.Unlock()
|
||||
}
|
||||
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return errConnClosing
|
||||
return
|
||||
}
|
||||
ac.printf("connecting")
|
||||
if ac.state != connectivity.Connecting {
|
||||
ac.state = connectivity.Connecting
|
||||
|
||||
// If the connection is READY, a failure must have occurred.
|
||||
// Otherwise, we'll consider this is a transient failure when:
|
||||
// We've exhausted all addresses
|
||||
// We're in CONNECTING
|
||||
// And it's not the very first addr to try TODO(deklerk) find a better way to do this than checking ac.successfulHandshake
|
||||
if ac.state == connectivity.Ready || (ac.addrIdx == len(ac.addrs)-1 && ac.state == connectivity.Connecting && !ac.successfulHandshake) {
|
||||
ac.updateConnectivityState(connectivity.TransientFailure)
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
}
|
||||
// copy ac.addrs in case of race
|
||||
addrsIter := make([]resolver.Address, len(ac.addrs))
|
||||
copy(addrsIter, ac.addrs)
|
||||
copts := ac.dopts.copts
|
||||
ac.transport = nil
|
||||
ac.mu.Unlock()
|
||||
connected, err := ac.createTransport(connectRetryNum, ridx, backoffDeadline, connectDeadline, addrsIter, copts, resetBackoff)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
if err := ac.nextAddr(); err != nil {
|
||||
return
|
||||
}
|
||||
if connected {
|
||||
return nil
|
||||
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
backoffIdx := ac.backoffIdx
|
||||
backoffFor := ac.dopts.bs.Backoff(backoffIdx)
|
||||
|
||||
// This will be the duration that dial gets to finish.
|
||||
dialDuration := getMinConnectTimeout()
|
||||
if backoffFor > dialDuration {
|
||||
// Give dial more time as we keep failing to connect.
|
||||
dialDuration = backoffFor
|
||||
}
|
||||
start := time.Now()
|
||||
connectDeadline := start.Add(dialDuration)
|
||||
ac.backoffDeadline = start.Add(backoffFor)
|
||||
ac.connectDeadline = connectDeadline
|
||||
|
||||
ac.mu.Unlock()
|
||||
|
||||
ac.cc.mu.RLock()
|
||||
ac.dopts.copts.KeepaliveParams = ac.cc.mkp
|
||||
ac.cc.mu.RUnlock()
|
||||
|
||||
ac.mu.Lock()
|
||||
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
if ac.state != connectivity.Connecting {
|
||||
ac.updateConnectivityState(connectivity.Connecting)
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
}
|
||||
|
||||
addr := ac.addrs[ac.addrIdx]
|
||||
copts := ac.dopts.copts
|
||||
if ac.scopts.CredsBundle != nil {
|
||||
copts.CredsBundle = ac.scopts.CredsBundle
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
|
||||
if channelz.IsOn() {
|
||||
channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Subchannel picks a new address %q to connect", addr.Addr),
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
|
||||
if err := ac.createTransport(backoffIdx, addr, copts, connectDeadline); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// createTransport creates a connection to one of the backends in addrs.
|
||||
// It returns true if a connection was established.
|
||||
func (ac *addrConn) createTransport(connectRetryNum, ridx int, backoffDeadline, connectDeadline time.Time, addrs []resolver.Address, copts transport.ConnectOptions, resetBackoff chan struct{}) (bool, error) {
|
||||
for i := ridx; i < len(addrs); i++ {
|
||||
addr := addrs[i]
|
||||
target := transport.TargetInfo{
|
||||
Addr: addr.Addr,
|
||||
Metadata: addr.Metadata,
|
||||
Authority: ac.cc.authority,
|
||||
func (ac *addrConn) createTransport(backoffNum int, addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) error {
|
||||
oneReset := sync.Once{}
|
||||
skipReset := make(chan struct{})
|
||||
allowedToReset := make(chan struct{})
|
||||
prefaceReceived := make(chan struct{})
|
||||
onCloseCalled := make(chan struct{})
|
||||
|
||||
var prefaceMu sync.Mutex
|
||||
var serverPrefaceReceived bool
|
||||
var clientPrefaceWrote bool
|
||||
|
||||
onGoAway := func(r transport.GoAwayReason) {
|
||||
ac.mu.Lock()
|
||||
ac.adjustParams(r)
|
||||
ac.mu.Unlock()
|
||||
select {
|
||||
case <-skipReset: // The outer resetTransport loop will handle reconnection.
|
||||
return
|
||||
case <-allowedToReset: // We're in the clear to reset.
|
||||
go oneReset.Do(func() { ac.resetTransport(false) })
|
||||
}
|
||||
done := make(chan struct{})
|
||||
onPrefaceReceipt := func() {
|
||||
ac.mu.Lock()
|
||||
close(done)
|
||||
if !ac.backoffDeadline.IsZero() {
|
||||
// If we haven't already started reconnecting to
|
||||
// other backends.
|
||||
// Note, this can happen when writer notices an error
|
||||
// and triggers resetTransport while at the same time
|
||||
// reader receives the preface and invokes this closure.
|
||||
ac.backoffDeadline = time.Time{}
|
||||
ac.connectDeadline = time.Time{}
|
||||
ac.connectRetryNum = 0
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
}
|
||||
|
||||
prefaceTimer := time.NewTimer(connectDeadline.Sub(time.Now()))
|
||||
|
||||
onClose := func() {
|
||||
close(onCloseCalled)
|
||||
prefaceTimer.Stop()
|
||||
|
||||
select {
|
||||
case <-skipReset: // The outer resetTransport loop will handle reconnection.
|
||||
return
|
||||
case <-allowedToReset: // We're in the clear to reset.
|
||||
oneReset.Do(func() { ac.resetTransport(false) })
|
||||
}
|
||||
// Do not cancel in the success path because of
|
||||
// this issue in Go1.6: https://github.com/golang/go/issues/15078.
|
||||
connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline)
|
||||
if channelz.IsOn() {
|
||||
copts.ChannelzParentID = ac.channelzID
|
||||
}
|
||||
|
||||
target := transport.TargetInfo{
|
||||
Addr: addr.Addr,
|
||||
Metadata: addr.Metadata,
|
||||
Authority: ac.cc.authority,
|
||||
}
|
||||
|
||||
onPrefaceReceipt := func() {
|
||||
close(prefaceReceived)
|
||||
prefaceTimer.Stop()
|
||||
|
||||
// TODO(deklerk): optimization; does anyone else actually use this lock? maybe we can just remove it for this scope
|
||||
ac.mu.Lock()
|
||||
|
||||
prefaceMu.Lock()
|
||||
serverPrefaceReceived = true
|
||||
if clientPrefaceWrote {
|
||||
ac.successfulHandshake = true
|
||||
ac.backoffDeadline = time.Time{}
|
||||
ac.connectDeadline = time.Time{}
|
||||
ac.addrIdx = 0
|
||||
ac.backoffIdx = 0
|
||||
}
|
||||
newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, target, copts, onPrefaceReceipt)
|
||||
if err != nil {
|
||||
cancel()
|
||||
ac.cc.blockingpicker.updateConnectionError(err)
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
// ac.tearDown(...) has been invoked.
|
||||
ac.mu.Unlock()
|
||||
return false, errConnClosing
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
grpclog.Warningf("grpc: addrConn.createTransport failed to connect to %v. Err :%v. Reconnecting...", addr, err)
|
||||
continue
|
||||
prefaceMu.Unlock()
|
||||
|
||||
ac.mu.Unlock()
|
||||
}
|
||||
|
||||
// Do not cancel in the success path because of this issue in Go1.6: https://github.com/golang/go/issues/15078.
|
||||
connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline)
|
||||
if channelz.IsOn() {
|
||||
copts.ChannelzParentID = ac.channelzID
|
||||
}
|
||||
|
||||
newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, target, copts, onPrefaceReceipt, onGoAway, onClose)
|
||||
|
||||
if err == nil {
|
||||
prefaceMu.Lock()
|
||||
clientPrefaceWrote = true
|
||||
if serverPrefaceReceived {
|
||||
ac.successfulHandshake = true
|
||||
}
|
||||
prefaceMu.Unlock()
|
||||
|
||||
if ac.dopts.waitForHandshake {
|
||||
select {
|
||||
case <-done:
|
||||
case <-connectCtx.Done():
|
||||
// Didn't receive server preface, must kill this new transport now.
|
||||
grpclog.Warningf("grpc: addrConn.createTransport failed to receive server preface before deadline.")
|
||||
case <-prefaceTimer.C:
|
||||
// We didn't get the preface in time.
|
||||
newTr.Close()
|
||||
continue
|
||||
case <-ac.ctx.Done():
|
||||
err = errors.New("timed out waiting for server handshake")
|
||||
case <-prefaceReceived:
|
||||
// We got the preface - huzzah! things are good.
|
||||
case <-onCloseCalled:
|
||||
// The transport has already closed - noop.
|
||||
close(allowedToReset)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
go func() {
|
||||
select {
|
||||
case <-prefaceTimer.C:
|
||||
// We didn't get the preface in time.
|
||||
newTr.Close()
|
||||
case <-prefaceReceived:
|
||||
// We got the preface just in the nick of time - huzzah!
|
||||
case <-onCloseCalled:
|
||||
// The transport has already closed - noop.
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// newTr is either nil, or closed.
|
||||
cancel()
|
||||
ac.cc.blockingpicker.updateConnectionError(err)
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
// ac.tearDown(...) has been invoked.
|
||||
ac.mu.Unlock()
|
||||
// ac.tearDonn(...) has been invoked.
|
||||
newTr.Close()
|
||||
return false, errConnClosing
|
||||
}
|
||||
ac.printf("ready")
|
||||
ac.state = connectivity.Ready
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
ac.transport = newTr
|
||||
ac.curAddr = addr
|
||||
if ac.ready != nil {
|
||||
close(ac.ready)
|
||||
ac.ready = nil
|
||||
}
|
||||
select {
|
||||
case <-done:
|
||||
// If the server has responded back with preface already,
|
||||
// don't set the reconnect parameters.
|
||||
default:
|
||||
ac.connectRetryNum = connectRetryNum
|
||||
ac.backoffDeadline = backoffDeadline
|
||||
ac.connectDeadline = connectDeadline
|
||||
ac.reconnectIdx = i + 1 // Start reconnecting from the next backend in the list.
|
||||
|
||||
// We don't want to reset during this close because we prefer to kick out of this function and let the loop
|
||||
// in resetTransport take care of reconnecting.
|
||||
close(skipReset)
|
||||
|
||||
return errConnClosing
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
return true, nil
|
||||
grpclog.Warningf("grpc: addrConn.createTransport failed to connect to %v. Err :%v. Reconnecting...", addr, err)
|
||||
|
||||
// We don't want to reset during this close because we prefer to kick out of this function and let the loop
|
||||
// in resetTransport take care of reconnecting.
|
||||
close(skipReset)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
ac.mu.Lock()
|
||||
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return false, errConnClosing
|
||||
|
||||
// We don't want to reset during this close because we prefer to kick out of this function and let the loop
|
||||
// in resetTransport take care of reconnecting.
|
||||
close(skipReset)
|
||||
|
||||
newTr.Close()
|
||||
return errConnClosing
|
||||
}
|
||||
ac.state = connectivity.TransientFailure
|
||||
|
||||
ac.updateConnectivityState(connectivity.Ready)
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
ac.cc.resolveNow(resolver.ResolveNowOption{})
|
||||
if ac.ready != nil {
|
||||
close(ac.ready)
|
||||
ac.ready = nil
|
||||
ac.transport = newTr
|
||||
ac.curAddr = addr
|
||||
|
||||
ac.mu.Unlock()
|
||||
|
||||
// Ok, _now_ we will finally let the transport reset if it encounters a closable error. Without this, the reader
|
||||
// goroutine failing races with all the code in this method that sets the connection to "ready".
|
||||
close(allowedToReset)
|
||||
return nil
|
||||
}
|
||||
|
||||
// nextAddr increments the addrIdx if there are more addresses to try. If
|
||||
// there are no more addrs to try it will re-resolve, set addrIdx to 0, and
|
||||
// increment the backoffIdx.
|
||||
//
|
||||
// nextAddr must be called without ac.mu being held.
|
||||
func (ac *addrConn) nextAddr() error {
|
||||
ac.mu.Lock()
|
||||
|
||||
// If a handshake has been observed, we expect the counters to have manually
|
||||
// been reset so we'll just return, since we want the next usage to start
|
||||
// at index 0.
|
||||
if ac.successfulHandshake {
|
||||
ac.successfulHandshake = false
|
||||
ac.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
if ac.addrIdx < len(ac.addrs)-1 {
|
||||
ac.addrIdx++
|
||||
ac.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
ac.addrIdx = 0
|
||||
ac.backoffIdx++
|
||||
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return errConnClosing
|
||||
}
|
||||
ac.cc.resolveNow(resolver.ResolveNowOption{})
|
||||
backoffDeadline := ac.backoffDeadline
|
||||
b := ac.resetBackoff
|
||||
ac.mu.Unlock()
|
||||
timer := time.NewTimer(backoffDeadline.Sub(time.Now()))
|
||||
select {
|
||||
case <-timer.C:
|
||||
case <-resetBackoff:
|
||||
case <-b:
|
||||
timer.Stop()
|
||||
case <-ac.ctx.Done():
|
||||
timer.Stop()
|
||||
return false, ac.ctx.Err()
|
||||
return ac.ctx.Err()
|
||||
}
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ac *addrConn) resetConnectBackoff() {
|
||||
ac.mu.Lock()
|
||||
close(ac.resetBackoff)
|
||||
ac.backoffIdx = 0
|
||||
ac.resetBackoff = make(chan struct{})
|
||||
ac.connectRetryNum = 0
|
||||
ac.mu.Unlock()
|
||||
}
|
||||
|
||||
// Run in a goroutine to track the error in transport and create the
|
||||
// new transport if an error happens. It returns when the channel is closing.
|
||||
func (ac *addrConn) transportMonitor() {
|
||||
for {
|
||||
var timer *time.Timer
|
||||
var cdeadline <-chan time.Time
|
||||
ac.mu.Lock()
|
||||
t := ac.transport
|
||||
if !ac.connectDeadline.IsZero() {
|
||||
timer = time.NewTimer(ac.connectDeadline.Sub(time.Now()))
|
||||
cdeadline = timer.C
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
// Block until we receive a goaway or an error occurs.
|
||||
select {
|
||||
case <-t.GoAway():
|
||||
done := t.Error()
|
||||
cleanup := t.Close
|
||||
// Since this transport will be orphaned (won't have a transportMonitor)
|
||||
// we need to launch a goroutine to keep track of clientConn.Close()
|
||||
// happening since it might not be noticed by any other goroutine for a while.
|
||||
go func() {
|
||||
<-done
|
||||
cleanup()
|
||||
}()
|
||||
case <-t.Error():
|
||||
// In case this is triggered because clientConn.Close()
|
||||
// was called, we want to immeditately close the transport
|
||||
// since no other goroutine might notice it for a while.
|
||||
t.Close()
|
||||
case <-cdeadline:
|
||||
ac.mu.Lock()
|
||||
// This implies that client received server preface.
|
||||
if ac.backoffDeadline.IsZero() {
|
||||
ac.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
timer = nil
|
||||
// No server preface received until deadline.
|
||||
// Kill the connection.
|
||||
grpclog.Warningf("grpc: addrConn.transportMonitor didn't get server preface after waiting. Closing the new transport now.")
|
||||
t.Close()
|
||||
}
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
}
|
||||
// If a GoAway happened, regardless of error, adjust our keepalive
|
||||
// parameters as appropriate.
|
||||
select {
|
||||
case <-t.GoAway():
|
||||
ac.adjustParams(t.GetGoAwayReason())
|
||||
default:
|
||||
}
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return
|
||||
}
|
||||
// Set connectivity state to TransientFailure before calling
|
||||
// resetTransport. Transition READY->CONNECTING is not valid.
|
||||
ac.state = connectivity.TransientFailure
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
ac.cc.resolveNow(resolver.ResolveNowOption{})
|
||||
ac.curAddr = resolver.Address{}
|
||||
ac.mu.Unlock()
|
||||
if err := ac.resetTransport(); err != nil {
|
||||
ac.mu.Lock()
|
||||
ac.printf("transport exiting: %v", err)
|
||||
ac.mu.Unlock()
|
||||
grpclog.Warningf("grpc: addrConn.transportMonitor exits due to: %v", err)
|
||||
if err != errConnClosing {
|
||||
// Keep this ac in cc.conns, to get the reason it's torn down.
|
||||
ac.tearDown(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getReadyTransport returns the transport if ac's state is READY.
|
||||
// Otherwise it returns nil, false.
|
||||
// If ac's state is IDLE, it will trigger ac to connect.
|
||||
func (ac *addrConn) getReadyTransport() (transport.ClientTransport, bool) {
|
||||
ac.mu.Lock()
|
||||
if ac.state == connectivity.Ready {
|
||||
if ac.state == connectivity.Ready && ac.transport != nil {
|
||||
t := ac.transport
|
||||
ac.mu.Unlock()
|
||||
return t, true
|
||||
|
|
@ -1161,34 +1274,42 @@ func (ac *addrConn) getReadyTransport() (transport.ClientTransport, bool) {
|
|||
// tight loop.
|
||||
// tearDown doesn't remove ac from ac.cc.conns.
|
||||
func (ac *addrConn) tearDown(err error) {
|
||||
ac.cancel()
|
||||
ac.mu.Lock()
|
||||
defer ac.mu.Unlock()
|
||||
if ac.state == connectivity.Shutdown {
|
||||
ac.mu.Unlock()
|
||||
return
|
||||
}
|
||||
// We have to set the state to Shutdown before anything else to prevent races
|
||||
// between setting the state and logic that waits on context cancelation / etc.
|
||||
ac.updateConnectivityState(connectivity.Shutdown)
|
||||
ac.cancel()
|
||||
ac.tearDownErr = err
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
ac.curAddr = resolver.Address{}
|
||||
if err == errConnDrain && ac.transport != nil {
|
||||
// GracefulClose(...) may be executed multiple times when
|
||||
// i) receiving multiple GoAway frames from the server; or
|
||||
// ii) there are concurrent name resolver/Balancer triggered
|
||||
// address removal and GoAway.
|
||||
// We have to unlock and re-lock here because GracefulClose => Close => onClose, which requires locking ac.mu.
|
||||
ac.mu.Unlock()
|
||||
ac.transport.GracefulClose()
|
||||
}
|
||||
ac.state = connectivity.Shutdown
|
||||
ac.tearDownErr = err
|
||||
ac.cc.handleSubConnStateChange(ac.acbw, ac.state)
|
||||
if ac.events != nil {
|
||||
ac.events.Finish()
|
||||
ac.events = nil
|
||||
}
|
||||
if ac.ready != nil {
|
||||
close(ac.ready)
|
||||
ac.ready = nil
|
||||
ac.mu.Lock()
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: "Subchannel Deleted",
|
||||
Severity: channelz.CtINFO,
|
||||
Parent: &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Subchanel(id:%d) deleted", ac.channelzID),
|
||||
Severity: channelz.CtINFO,
|
||||
},
|
||||
})
|
||||
// TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to
|
||||
// the entity beng deleted, and thus prevent it from being deleted right away.
|
||||
channelz.RemoveEntry(ac.channelzID)
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
}
|
||||
|
||||
func (ac *addrConn) getState() connectivity.State {
|
||||
|
|
|
|||
19
vendor/google.golang.org/grpc/credentials/credentials.go
generated
vendored
19
vendor/google.golang.org/grpc/credentials/credentials.go
generated
vendored
|
|
@ -108,6 +108,25 @@ type TransportCredentials interface {
|
|||
OverrideServerName(string) error
|
||||
}
|
||||
|
||||
// Bundle is a combination of TransportCredentials and PerRPCCredentials.
|
||||
//
|
||||
// It also contains a mode switching method, so it can be used as a combination
|
||||
// of different credential policies.
|
||||
//
|
||||
// Bundle cannot be used together with individual TransportCredentials.
|
||||
// PerRPCCredentials from Bundle will be appended to other PerRPCCredentials.
|
||||
//
|
||||
// This API is experimental.
|
||||
type Bundle interface {
|
||||
TransportCredentials() TransportCredentials
|
||||
PerRPCCredentials() PerRPCCredentials
|
||||
// NewWithMode should make a copy of Bundle, and switch mode. Modifying the
|
||||
// existing Bundle may cause races.
|
||||
//
|
||||
// NewWithMode returns nil if the requested mode is not supported.
|
||||
NewWithMode(mode string) (Bundle, error)
|
||||
}
|
||||
|
||||
// TLSInfo contains the auth information for a TLS authenticated connection.
|
||||
// It implements the AuthInfo interface.
|
||||
type TLSInfo struct {
|
||||
|
|
|
|||
14
vendor/google.golang.org/grpc/dialoptions.go
generated
vendored
14
vendor/google.golang.org/grpc/dialoptions.go
generated
vendored
|
|
@ -286,7 +286,8 @@ func WithInsecure() DialOption {
|
|||
}
|
||||
|
||||
// WithTransportCredentials returns a DialOption which configures a connection
|
||||
// level security credentials (e.g., TLS/SSL).
|
||||
// level security credentials (e.g., TLS/SSL). This should not be used together
|
||||
// with WithCredentialsBundle.
|
||||
func WithTransportCredentials(creds credentials.TransportCredentials) DialOption {
|
||||
return newFuncDialOption(func(o *dialOptions) {
|
||||
o.copts.TransportCredentials = creds
|
||||
|
|
@ -301,6 +302,17 @@ func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption {
|
|||
})
|
||||
}
|
||||
|
||||
// WithCredentialsBundle returns a DialOption to set a credentials bundle for
|
||||
// the ClientConn.WithCreds. This should not be used together with
|
||||
// WithTransportCredentials.
|
||||
//
|
||||
// This API is experimental.
|
||||
func WithCredentialsBundle(b credentials.Bundle) DialOption {
|
||||
return newFuncDialOption(func(o *dialOptions) {
|
||||
o.copts.CredsBundle = b
|
||||
})
|
||||
}
|
||||
|
||||
// WithTimeout returns a DialOption that configures a timeout for dialing a
|
||||
// ClientConn initially. This is valid if and only if WithBlock() is present.
|
||||
//
|
||||
|
|
|
|||
2
vendor/google.golang.org/grpc/install_gae.sh
generated
vendored
2
vendor/google.golang.org/grpc/install_gae.sh
generated
vendored
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
TMP=$(mktemp -d /tmp/sdk.XXX) \
|
||||
&& curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.64.zip" \
|
||||
&& curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip" \
|
||||
&& unzip -q $TMP.zip -d $TMP \
|
||||
&& export PATH="$PATH:$TMP/go_appengine"
|
||||
|
|
|
|||
103
vendor/google.golang.org/grpc/internal/channelz/funcs.go
generated
vendored
103
vendor/google.golang.org/grpc/internal/channelz/funcs.go
generated
vendored
|
|
@ -27,16 +27,22 @@ import (
|
|||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxTraceEntry int32 = 30
|
||||
)
|
||||
|
||||
var (
|
||||
db dbWrapper
|
||||
idGen idGenerator
|
||||
// EntryPerPage defines the number of channelz entries to be shown on a web page.
|
||||
EntryPerPage = 50
|
||||
curState int32
|
||||
EntryPerPage = 50
|
||||
curState int32
|
||||
maxTraceEntry = defaultMaxTraceEntry
|
||||
)
|
||||
|
||||
// TurnOn turns on channelz data collection.
|
||||
|
|
@ -52,6 +58,22 @@ func IsOn() bool {
|
|||
return atomic.CompareAndSwapInt32(&curState, 1, 1)
|
||||
}
|
||||
|
||||
// SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel).
|
||||
// Setting it to 0 will disable channel tracing.
|
||||
func SetMaxTraceEntry(i int32) {
|
||||
atomic.StoreInt32(&maxTraceEntry, i)
|
||||
}
|
||||
|
||||
// ResetMaxTraceEntryToDefault resets the maximum number of trace entry per entity to default.
|
||||
func ResetMaxTraceEntryToDefault() {
|
||||
atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry)
|
||||
}
|
||||
|
||||
func getMaxTraceEntry() int {
|
||||
i := atomic.LoadInt32(&maxTraceEntry)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
// dbWarpper wraps around a reference to internal channelz data storage, and
|
||||
// provide synchronized functionality to set and get the reference.
|
||||
type dbWrapper struct {
|
||||
|
|
@ -146,6 +168,7 @@ func RegisterChannel(c Channel, pid int64, ref string) int64 {
|
|||
nestedChans: make(map[int64]string),
|
||||
id: id,
|
||||
pid: pid,
|
||||
trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())},
|
||||
}
|
||||
if pid == 0 {
|
||||
db.get().addChannel(id, cn, true, pid, ref)
|
||||
|
|
@ -170,6 +193,7 @@ func RegisterSubChannel(c Channel, pid int64, ref string) int64 {
|
|||
sockets: make(map[int64]string),
|
||||
id: id,
|
||||
pid: pid,
|
||||
trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())},
|
||||
}
|
||||
db.get().addSubChannel(id, sc, pid, ref)
|
||||
return id
|
||||
|
|
@ -226,6 +250,24 @@ func RemoveEntry(id int64) {
|
|||
db.get().removeEntry(id)
|
||||
}
|
||||
|
||||
// TraceEventDesc is what the caller of AddTraceEvent should provide to describe the event to be added
|
||||
// to the channel trace.
|
||||
// The Parent field is optional. It is used for event that will be recorded in the entity's parent
|
||||
// trace also.
|
||||
type TraceEventDesc struct {
|
||||
Desc string
|
||||
Severity Severity
|
||||
Parent *TraceEventDesc
|
||||
}
|
||||
|
||||
// AddTraceEvent adds trace related to the entity with specified id, using the provided TraceEventDesc.
|
||||
func AddTraceEvent(id int64, desc *TraceEventDesc) {
|
||||
if getMaxTraceEntry() == 0 {
|
||||
return
|
||||
}
|
||||
db.get().traceEvent(id, desc)
|
||||
}
|
||||
|
||||
// channelMap is the storage data structure for channelz.
|
||||
// Methods of channelMap can be divided in two two categories with respect to locking.
|
||||
// 1. Methods acquire the global lock.
|
||||
|
|
@ -251,6 +293,7 @@ func (c *channelMap) addServer(id int64, s *server) {
|
|||
func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64, ref string) {
|
||||
c.mu.Lock()
|
||||
cn.cm = c
|
||||
cn.trace.cm = c
|
||||
c.channels[id] = cn
|
||||
if isTopChannel {
|
||||
c.topLevelChannels[id] = struct{}{}
|
||||
|
|
@ -263,6 +306,7 @@ func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid in
|
|||
func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref string) {
|
||||
c.mu.Lock()
|
||||
sc.cm = c
|
||||
sc.trace.cm = c
|
||||
c.subChannels[id] = sc
|
||||
c.findEntry(pid).addChild(id, sc)
|
||||
c.mu.Unlock()
|
||||
|
|
@ -284,16 +328,25 @@ func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64, ref
|
|||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// removeEntry triggers the removal of an entry, which may not indeed delete the
|
||||
// entry, if it has to wait on the deletion of its children, or may lead to a chain
|
||||
// of entry deletion. For example, deleting the last socket of a gracefully shutting
|
||||
// down server will lead to the server being also deleted.
|
||||
// removeEntry triggers the removal of an entry, which may not indeed delete the entry, if it has to
|
||||
// wait on the deletion of its children and until no other entity's channel trace references it.
|
||||
// It may lead to a chain of entry deletion. For example, deleting the last socket of a gracefully
|
||||
// shutting down server will lead to the server being also deleted.
|
||||
func (c *channelMap) removeEntry(id int64) {
|
||||
c.mu.Lock()
|
||||
c.findEntry(id).triggerDelete()
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// c.mu must be held by the caller
|
||||
func (c *channelMap) decrTraceRefCount(id int64) {
|
||||
e := c.findEntry(id)
|
||||
if v, ok := e.(tracedChannel); ok {
|
||||
v.decrTraceRefCount()
|
||||
e.deleteSelfIfReady()
|
||||
}
|
||||
}
|
||||
|
||||
// c.mu must be held by the caller.
|
||||
func (c *channelMap) findEntry(id int64) entry {
|
||||
var v entry
|
||||
|
|
@ -347,6 +400,39 @@ func (c *channelMap) deleteEntry(id int64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *channelMap) traceEvent(id int64, desc *TraceEventDesc) {
|
||||
c.mu.Lock()
|
||||
child := c.findEntry(id)
|
||||
childTC, ok := child.(tracedChannel)
|
||||
if !ok {
|
||||
c.mu.Unlock()
|
||||
return
|
||||
}
|
||||
childTC.getChannelTrace().append(&TraceEvent{Desc: desc.Desc, Severity: desc.Severity, Timestamp: time.Now()})
|
||||
if desc.Parent != nil {
|
||||
parent := c.findEntry(child.getParentID())
|
||||
var chanType RefChannelType
|
||||
switch child.(type) {
|
||||
case *channel:
|
||||
chanType = RefChannel
|
||||
case *subChannel:
|
||||
chanType = RefSubChannel
|
||||
}
|
||||
if parentTC, ok := parent.(tracedChannel); ok {
|
||||
parentTC.getChannelTrace().append(&TraceEvent{
|
||||
Desc: desc.Parent.Desc,
|
||||
Severity: desc.Parent.Severity,
|
||||
Timestamp: time.Now(),
|
||||
RefID: id,
|
||||
RefName: childTC.getRefName(),
|
||||
RefType: chanType,
|
||||
})
|
||||
childTC.incrTraceRefCount()
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
type int64Slice []int64
|
||||
|
||||
func (s int64Slice) Len() int { return len(s) }
|
||||
|
|
@ -408,6 +494,7 @@ func (c *channelMap) GetTopChannels(id int64) ([]*ChannelMetric, bool) {
|
|||
t[i].ChannelData = cn.c.ChannelzMetric()
|
||||
t[i].ID = cn.id
|
||||
t[i].RefName = cn.refName
|
||||
t[i].Trace = cn.trace.dumpData()
|
||||
}
|
||||
return t, end
|
||||
}
|
||||
|
|
@ -470,7 +557,7 @@ func (c *channelMap) GetServerSockets(id int64, startID int64) ([]*SocketMetric,
|
|||
for k := range svrskts {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
sort.Sort((int64Slice(ids)))
|
||||
sort.Sort(int64Slice(ids))
|
||||
idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id })
|
||||
count := 0
|
||||
var end bool
|
||||
|
|
@ -518,6 +605,7 @@ func (c *channelMap) GetChannel(id int64) *ChannelMetric {
|
|||
cm.ChannelData = cn.c.ChannelzMetric()
|
||||
cm.ID = cn.id
|
||||
cm.RefName = cn.refName
|
||||
cm.Trace = cn.trace.dumpData()
|
||||
return cm
|
||||
}
|
||||
|
||||
|
|
@ -536,6 +624,7 @@ func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric {
|
|||
cm.ChannelData = sc.c.ChannelzMetric()
|
||||
cm.ID = sc.id
|
||||
cm.RefName = sc.refName
|
||||
cm.Trace = sc.trace.dumpData()
|
||||
return cm
|
||||
}
|
||||
|
||||
|
|
|
|||
311
vendor/google.golang.org/grpc/internal/channelz/types.go
generated
vendored
311
vendor/google.golang.org/grpc/internal/channelz/types.go
generated
vendored
|
|
@ -20,6 +20,8 @@ package channelz
|
|||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/connectivity"
|
||||
|
|
@ -40,6 +42,8 @@ type entry interface {
|
|||
// deleteSelfIfReady check whether triggerDelete() has been called before, and whether child
|
||||
// list is now empty. If both conditions are met, then delete self from database.
|
||||
deleteSelfIfReady()
|
||||
// getParentID returns parent ID of the entry. 0 value parent ID means no parent.
|
||||
getParentID() int64
|
||||
}
|
||||
|
||||
// dummyEntry is a fake entry to handle entry not found case.
|
||||
|
|
@ -73,6 +77,10 @@ func (*dummyEntry) deleteSelfIfReady() {
|
|||
// code should not reach here. deleteSelfIfReady is always called on an existing entry.
|
||||
}
|
||||
|
||||
func (*dummyEntry) getParentID() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ChannelMetric defines the info channelz provides for a specific Channel, which
|
||||
// includes ChannelInternalMetric and channelz-specific data, such as channelz id,
|
||||
// child list, etc.
|
||||
|
|
@ -95,6 +103,8 @@ type ChannelMetric struct {
|
|||
// Note current grpc implementation doesn't allow channel having sockets directly,
|
||||
// therefore, this is field is unused.
|
||||
Sockets map[int64]string
|
||||
// Trace contains the most recent traced events.
|
||||
Trace *ChannelTrace
|
||||
}
|
||||
|
||||
// SubChannelMetric defines the info channelz provides for a specific SubChannel,
|
||||
|
|
@ -121,6 +131,8 @@ type SubChannelMetric struct {
|
|||
// Sockets tracks the socket type children of this subchannel in the format of a map
|
||||
// from socket channelz id to corresponding reference string.
|
||||
Sockets map[int64]string
|
||||
// Trace contains the most recent traced events.
|
||||
Trace *ChannelTrace
|
||||
}
|
||||
|
||||
// ChannelInternalMetric defines the struct that the implementor of Channel interface
|
||||
|
|
@ -138,7 +150,35 @@ type ChannelInternalMetric struct {
|
|||
CallsFailed int64
|
||||
// The last time a call was started on the channel.
|
||||
LastCallStartedTimestamp time.Time
|
||||
//TODO: trace
|
||||
}
|
||||
|
||||
// ChannelTrace stores traced events on a channel/subchannel and related info.
|
||||
type ChannelTrace struct {
|
||||
// EventNum is the number of events that ever got traced (i.e. including those that have been deleted)
|
||||
EventNum int64
|
||||
// CreationTime is the creation time of the trace.
|
||||
CreationTime time.Time
|
||||
// Events stores the most recent trace events (up to $maxTraceEntry, newer event will overwrite the
|
||||
// oldest one)
|
||||
Events []*TraceEvent
|
||||
}
|
||||
|
||||
// TraceEvent represent a single trace event
|
||||
type TraceEvent struct {
|
||||
// Desc is a simple description of the trace event.
|
||||
Desc string
|
||||
// Severity states the severity of this trace event.
|
||||
Severity Severity
|
||||
// Timestamp is the event time.
|
||||
Timestamp time.Time
|
||||
// RefID is the id of the entity that gets referenced in the event. RefID is 0 if no other entity is
|
||||
// involved in this event.
|
||||
// e.g. SubChannel (id: 4[]) Created. --> RefID = 4, RefName = "" (inside [])
|
||||
RefID int64
|
||||
// RefName is the reference name for the entity that gets referenced in the event.
|
||||
RefName string
|
||||
// RefType indicates the referenced entity type, i.e Channel or SubChannel.
|
||||
RefType RefChannelType
|
||||
}
|
||||
|
||||
// Channel is the interface that should be satisfied in order to be tracked by
|
||||
|
|
@ -147,6 +187,12 @@ type Channel interface {
|
|||
ChannelzMetric() *ChannelInternalMetric
|
||||
}
|
||||
|
||||
type dummyChannel struct{}
|
||||
|
||||
func (d *dummyChannel) ChannelzMetric() *ChannelInternalMetric {
|
||||
return &ChannelInternalMetric{}
|
||||
}
|
||||
|
||||
type channel struct {
|
||||
refName string
|
||||
c Channel
|
||||
|
|
@ -156,6 +202,10 @@ type channel struct {
|
|||
id int64
|
||||
pid int64
|
||||
cm *channelMap
|
||||
trace *channelTrace
|
||||
// traceRefCount is the number of trace events that reference this channel.
|
||||
// Non-zero traceRefCount means the trace of this channel cannot be deleted.
|
||||
traceRefCount int32
|
||||
}
|
||||
|
||||
func (c *channel) addChild(id int64, e entry) {
|
||||
|
|
@ -180,25 +230,96 @@ func (c *channel) triggerDelete() {
|
|||
c.deleteSelfIfReady()
|
||||
}
|
||||
|
||||
func (c *channel) deleteSelfIfReady() {
|
||||
func (c *channel) getParentID() int64 {
|
||||
return c.pid
|
||||
}
|
||||
|
||||
// deleteSelfFromTree tries to delete the channel from the channelz entry relation tree, which means
|
||||
// deleting the channel reference from its parent's child list.
|
||||
//
|
||||
// In order for a channel to be deleted from the tree, it must meet the criteria that, removal of the
|
||||
// corresponding grpc object has been invoked, and the channel does not have any children left.
|
||||
//
|
||||
// The returned boolean value indicates whether the channel has been successfully deleted from tree.
|
||||
func (c *channel) deleteSelfFromTree() (deleted bool) {
|
||||
if !c.closeCalled || len(c.subChans)+len(c.nestedChans) != 0 {
|
||||
return
|
||||
return false
|
||||
}
|
||||
c.cm.deleteEntry(c.id)
|
||||
// not top channel
|
||||
if c.pid != 0 {
|
||||
c.cm.findEntry(c.pid).deleteChild(c.id)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// deleteSelfFromMap checks whether it is valid to delete the channel from the map, which means
|
||||
// deleting the channel from channelz's tracking entirely. Users can no longer use id to query the
|
||||
// channel, and its memory will be garbage collected.
|
||||
//
|
||||
// The trace reference count of the channel must be 0 in order to be deleted from the map. This is
|
||||
// specified in the channel tracing gRFC that as long as some other trace has reference to an entity,
|
||||
// the trace of the referenced entity must not be deleted. In order to release the resource allocated
|
||||
// by grpc, the reference to the grpc object is reset to a dummy object.
|
||||
//
|
||||
// deleteSelfFromMap must be called after deleteSelfFromTree returns true.
|
||||
//
|
||||
// It returns a bool to indicate whether the channel can be safely deleted from map.
|
||||
func (c *channel) deleteSelfFromMap() (delete bool) {
|
||||
if c.getTraceRefCount() != 0 {
|
||||
c.c = &dummyChannel{}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// deleteSelfIfReady tries to delete the channel itself from the channelz database.
|
||||
// The delete process includes two steps:
|
||||
// 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its
|
||||
// parent's child list.
|
||||
// 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id
|
||||
// will return entry not found error.
|
||||
func (c *channel) deleteSelfIfReady() {
|
||||
if !c.deleteSelfFromTree() {
|
||||
return
|
||||
}
|
||||
if !c.deleteSelfFromMap() {
|
||||
return
|
||||
}
|
||||
c.cm.deleteEntry(c.id)
|
||||
c.trace.clear()
|
||||
}
|
||||
|
||||
func (c *channel) getChannelTrace() *channelTrace {
|
||||
return c.trace
|
||||
}
|
||||
|
||||
func (c *channel) incrTraceRefCount() {
|
||||
atomic.AddInt32(&c.traceRefCount, 1)
|
||||
}
|
||||
|
||||
func (c *channel) decrTraceRefCount() {
|
||||
atomic.AddInt32(&c.traceRefCount, -1)
|
||||
}
|
||||
|
||||
func (c *channel) getTraceRefCount() int {
|
||||
i := atomic.LoadInt32(&c.traceRefCount)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
func (c *channel) getRefName() string {
|
||||
return c.refName
|
||||
}
|
||||
|
||||
type subChannel struct {
|
||||
refName string
|
||||
c Channel
|
||||
closeCalled bool
|
||||
sockets map[int64]string
|
||||
id int64
|
||||
pid int64
|
||||
cm *channelMap
|
||||
refName string
|
||||
c Channel
|
||||
closeCalled bool
|
||||
sockets map[int64]string
|
||||
id int64
|
||||
pid int64
|
||||
cm *channelMap
|
||||
trace *channelTrace
|
||||
traceRefCount int32
|
||||
}
|
||||
|
||||
func (sc *subChannel) addChild(id int64, e entry) {
|
||||
|
|
@ -219,12 +340,82 @@ func (sc *subChannel) triggerDelete() {
|
|||
sc.deleteSelfIfReady()
|
||||
}
|
||||
|
||||
func (sc *subChannel) deleteSelfIfReady() {
|
||||
func (sc *subChannel) getParentID() int64 {
|
||||
return sc.pid
|
||||
}
|
||||
|
||||
// deleteSelfFromTree tries to delete the subchannel from the channelz entry relation tree, which
|
||||
// means deleting the subchannel reference from its parent's child list.
|
||||
//
|
||||
// In order for a subchannel to be deleted from the tree, it must meet the criteria that, removal of
|
||||
// the corresponding grpc object has been invoked, and the subchannel does not have any children left.
|
||||
//
|
||||
// The returned boolean value indicates whether the channel has been successfully deleted from tree.
|
||||
func (sc *subChannel) deleteSelfFromTree() (deleted bool) {
|
||||
if !sc.closeCalled || len(sc.sockets) != 0 {
|
||||
return false
|
||||
}
|
||||
sc.cm.findEntry(sc.pid).deleteChild(sc.id)
|
||||
return true
|
||||
}
|
||||
|
||||
// deleteSelfFromMap checks whether it is valid to delete the subchannel from the map, which means
|
||||
// deleting the subchannel from channelz's tracking entirely. Users can no longer use id to query
|
||||
// the subchannel, and its memory will be garbage collected.
|
||||
//
|
||||
// The trace reference count of the subchannel must be 0 in order to be deleted from the map. This is
|
||||
// specified in the channel tracing gRFC that as long as some other trace has reference to an entity,
|
||||
// the trace of the referenced entity must not be deleted. In order to release the resource allocated
|
||||
// by grpc, the reference to the grpc object is reset to a dummy object.
|
||||
//
|
||||
// deleteSelfFromMap must be called after deleteSelfFromTree returns true.
|
||||
//
|
||||
// It returns a bool to indicate whether the channel can be safely deleted from map.
|
||||
func (sc *subChannel) deleteSelfFromMap() (delete bool) {
|
||||
if sc.getTraceRefCount() != 0 {
|
||||
// free the grpc struct (i.e. addrConn)
|
||||
sc.c = &dummyChannel{}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// deleteSelfIfReady tries to delete the subchannel itself from the channelz database.
|
||||
// The delete process includes two steps:
|
||||
// 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from
|
||||
// its parent's child list.
|
||||
// 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup
|
||||
// by id will return entry not found error.
|
||||
func (sc *subChannel) deleteSelfIfReady() {
|
||||
if !sc.deleteSelfFromTree() {
|
||||
return
|
||||
}
|
||||
if !sc.deleteSelfFromMap() {
|
||||
return
|
||||
}
|
||||
sc.cm.deleteEntry(sc.id)
|
||||
sc.cm.findEntry(sc.pid).deleteChild(sc.id)
|
||||
sc.trace.clear()
|
||||
}
|
||||
|
||||
func (sc *subChannel) getChannelTrace() *channelTrace {
|
||||
return sc.trace
|
||||
}
|
||||
|
||||
func (sc *subChannel) incrTraceRefCount() {
|
||||
atomic.AddInt32(&sc.traceRefCount, 1)
|
||||
}
|
||||
|
||||
func (sc *subChannel) decrTraceRefCount() {
|
||||
atomic.AddInt32(&sc.traceRefCount, -1)
|
||||
}
|
||||
|
||||
func (sc *subChannel) getTraceRefCount() int {
|
||||
i := atomic.LoadInt32(&sc.traceRefCount)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
func (sc *subChannel) getRefName() string {
|
||||
return sc.refName
|
||||
}
|
||||
|
||||
// SocketMetric defines the info channelz provides for a specific Socket, which
|
||||
|
|
@ -318,6 +509,10 @@ func (ls *listenSocket) deleteSelfIfReady() {
|
|||
grpclog.Errorf("cannot call deleteSelfIfReady on a listen socket")
|
||||
}
|
||||
|
||||
func (ls *listenSocket) getParentID() int64 {
|
||||
return ls.pid
|
||||
}
|
||||
|
||||
type normalSocket struct {
|
||||
refName string
|
||||
s Socket
|
||||
|
|
@ -343,6 +538,10 @@ func (ns *normalSocket) deleteSelfIfReady() {
|
|||
grpclog.Errorf("cannot call deleteSelfIfReady on a normal socket")
|
||||
}
|
||||
|
||||
func (ns *normalSocket) getParentID() int64 {
|
||||
return ns.pid
|
||||
}
|
||||
|
||||
// ServerMetric defines the info channelz provides for a specific Server, which
|
||||
// includes ServerInternalMetric and channelz-specific data, such as channelz id,
|
||||
// child list, etc.
|
||||
|
|
@ -370,7 +569,6 @@ type ServerInternalMetric struct {
|
|||
CallsFailed int64
|
||||
// The last time a call was started on the server.
|
||||
LastCallStartedTimestamp time.Time
|
||||
//TODO: trace
|
||||
}
|
||||
|
||||
// Server is the interface to be satisfied in order to be tracked by channelz as
|
||||
|
|
@ -417,3 +615,88 @@ func (s *server) deleteSelfIfReady() {
|
|||
}
|
||||
s.cm.deleteEntry(s.id)
|
||||
}
|
||||
|
||||
func (s *server) getParentID() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type tracedChannel interface {
|
||||
getChannelTrace() *channelTrace
|
||||
incrTraceRefCount()
|
||||
decrTraceRefCount()
|
||||
getRefName() string
|
||||
}
|
||||
|
||||
type channelTrace struct {
|
||||
cm *channelMap
|
||||
createdTime time.Time
|
||||
eventCount int64
|
||||
mu sync.Mutex
|
||||
events []*TraceEvent
|
||||
}
|
||||
|
||||
func (c *channelTrace) append(e *TraceEvent) {
|
||||
c.mu.Lock()
|
||||
if len(c.events) == getMaxTraceEntry() {
|
||||
del := c.events[0]
|
||||
c.events = c.events[1:]
|
||||
if del.RefID != 0 {
|
||||
// start recursive cleanup in a goroutine to not block the call originated from grpc.
|
||||
go func() {
|
||||
// need to acquire c.cm.mu lock to call the unlocked attemptCleanup func.
|
||||
c.cm.mu.Lock()
|
||||
c.cm.decrTraceRefCount(del.RefID)
|
||||
c.cm.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
}
|
||||
e.Timestamp = time.Now()
|
||||
c.events = append(c.events, e)
|
||||
c.eventCount++
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func (c *channelTrace) clear() {
|
||||
c.mu.Lock()
|
||||
for _, e := range c.events {
|
||||
if e.RefID != 0 {
|
||||
// caller should have already held the c.cm.mu lock.
|
||||
c.cm.decrTraceRefCount(e.RefID)
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Severity is the severity level of a trace event.
|
||||
// The canonical enumeration of all valid values is here:
|
||||
// https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126.
|
||||
type Severity int
|
||||
|
||||
const (
|
||||
// CtUNKNOWN indicates unknown severity of a trace event.
|
||||
CtUNKNOWN Severity = iota
|
||||
// CtINFO indicates info level severity of a trace event.
|
||||
CtINFO
|
||||
// CtWarning indicates warning level severity of a trace event.
|
||||
CtWarning
|
||||
// CtError indicates error level severity of a trace event.
|
||||
CtError
|
||||
)
|
||||
|
||||
// RefChannelType is the type of the entity being referenced in a trace event.
|
||||
type RefChannelType int
|
||||
|
||||
const (
|
||||
// RefChannel indicates the referenced entity is a Channel.
|
||||
RefChannel RefChannelType = iota
|
||||
// RefSubChannel indicates the referenced entity is a SubChannel.
|
||||
RefSubChannel
|
||||
)
|
||||
|
||||
func (c *channelTrace) dumpData() *ChannelTrace {
|
||||
c.mu.Lock()
|
||||
ct := &ChannelTrace{EventNum: c.eventCount, CreationTime: c.createdTime}
|
||||
ct.Events = c.events[:len(c.events)]
|
||||
c.mu.Unlock()
|
||||
return ct
|
||||
}
|
||||
|
|
|
|||
16
vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go
generated
vendored
16
vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go
generated
vendored
|
|
@ -20,11 +20,13 @@
|
|||
|
||||
package channelz
|
||||
|
||||
import "google.golang.org/grpc/grpclog"
|
||||
import (
|
||||
"sync"
|
||||
|
||||
func init() {
|
||||
grpclog.Infof("Channelz: socket options are not supported on non-linux os and appengine.")
|
||||
}
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
|
||||
// SocketOptionData defines the struct to hold socket option data, and related
|
||||
// getter function to obtain info from fd.
|
||||
|
|
@ -35,4 +37,8 @@ type SocketOptionData struct {
|
|||
// Getsockopt defines the function to get socket options requested by channelz.
|
||||
// It is to be passed to syscall.RawConn.Control().
|
||||
// Windows OS doesn't support Socket Option
|
||||
func (s *SocketOptionData) Getsockopt(fd uintptr) {}
|
||||
func (s *SocketOptionData) Getsockopt(fd uintptr) {
|
||||
once.Do(func() {
|
||||
grpclog.Warningln("Channelz: socket options are not supported on non-linux os and appengine.")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
15
vendor/google.golang.org/grpc/internal/internal.go
generated
vendored
15
vendor/google.golang.org/grpc/internal/internal.go
generated
vendored
|
|
@ -20,9 +20,24 @@
|
|||
// symbols to avoid circular dependencies.
|
||||
package internal
|
||||
|
||||
import "golang.org/x/net/context"
|
||||
|
||||
var (
|
||||
// WithContextDialer is exported by clientconn.go
|
||||
WithContextDialer interface{} // func(context.Context, string) (net.Conn, error) grpc.DialOption
|
||||
// WithResolverBuilder is exported by clientconn.go
|
||||
WithResolverBuilder interface{} // func (resolver.Builder) grpc.DialOption
|
||||
// HealthCheckFunc is used to provide client-side LB channel health checking
|
||||
HealthCheckFunc func(ctx context.Context, newStream func() (interface{}, error), reportHealth func(bool), serviceName string) error
|
||||
)
|
||||
|
||||
const (
|
||||
// CredsBundleModeFallback switches GoogleDefaultCreds to fallback mode.
|
||||
CredsBundleModeFallback = "fallback"
|
||||
// CredsBundleModeBalancer switches GoogleDefaultCreds to grpclb balancer
|
||||
// mode.
|
||||
CredsBundleModeBalancer = "balancer"
|
||||
// CredsBundleModeBackendFromBalancer switches GoogleDefaultCreds to mode
|
||||
// that supports backend returned by grpclb balancer.
|
||||
CredsBundleModeBackendFromBalancer = "backend-from-balancer"
|
||||
)
|
||||
|
|
|
|||
57
vendor/google.golang.org/grpc/internal/transport/http2_client.go
generated
vendored
57
vendor/google.golang.org/grpc/internal/transport/http2_client.go
generated
vendored
|
|
@ -73,7 +73,7 @@ type http2Client struct {
|
|||
|
||||
isSecure bool
|
||||
|
||||
creds []credentials.PerRPCCredentials
|
||||
perRPCCreds []credentials.PerRPCCredentials
|
||||
|
||||
// Boolean to keep track of reading activity on transport.
|
||||
// 1 is true and 0 is false.
|
||||
|
|
@ -112,6 +112,9 @@ type http2Client struct {
|
|||
// Fields below are for channelz metric collection.
|
||||
channelzID int64 // channelz unique identification number
|
||||
czData *channelzData
|
||||
|
||||
onGoAway func(GoAwayReason)
|
||||
onClose func()
|
||||
}
|
||||
|
||||
func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error), addr string) (net.Conn, error) {
|
||||
|
|
@ -140,7 +143,7 @@ func isTemporary(err error) bool {
|
|||
// newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2
|
||||
// and starts to receive messages on it. Non-nil error returns if construction
|
||||
// fails.
|
||||
func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts ConnectOptions, onSuccess func()) (_ *http2Client, err error) {
|
||||
func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts ConnectOptions, onSuccess func(), onGoAway func(GoAwayReason), onClose func()) (_ *http2Client, err error) {
|
||||
scheme := "http"
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer func() {
|
||||
|
|
@ -166,9 +169,20 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne
|
|||
isSecure bool
|
||||
authInfo credentials.AuthInfo
|
||||
)
|
||||
if creds := opts.TransportCredentials; creds != nil {
|
||||
transportCreds := opts.TransportCredentials
|
||||
perRPCCreds := opts.PerRPCCredentials
|
||||
|
||||
if b := opts.CredsBundle; b != nil {
|
||||
if t := b.TransportCredentials(); t != nil {
|
||||
transportCreds = t
|
||||
}
|
||||
if t := b.PerRPCCredentials(); t != nil {
|
||||
perRPCCreds = append(perRPCCreds, t)
|
||||
}
|
||||
}
|
||||
if transportCreds != nil {
|
||||
scheme = "https"
|
||||
conn, authInfo, err = creds.ClientHandshake(connectCtx, addr.Authority, conn)
|
||||
conn, authInfo, err = transportCreds.ClientHandshake(connectCtx, addr.Authority, conn)
|
||||
if err != nil {
|
||||
return nil, connectionErrorf(isTemporary(err), err, "transport: authentication handshake failed: %v", err)
|
||||
}
|
||||
|
|
@ -213,7 +227,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne
|
|||
scheme: scheme,
|
||||
activeStreams: make(map[uint32]*Stream),
|
||||
isSecure: isSecure,
|
||||
creds: opts.PerRPCCredentials,
|
||||
perRPCCreds: perRPCCreds,
|
||||
kp: kp,
|
||||
statsHandler: opts.StatsHandler,
|
||||
initialWindowSize: initialWindowSize,
|
||||
|
|
@ -223,6 +237,8 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne
|
|||
streamQuota: defaultMaxStreamsClient,
|
||||
streamsQuotaAvailable: make(chan struct{}, 1),
|
||||
czData: new(channelzData),
|
||||
onGoAway: onGoAway,
|
||||
onClose: onClose,
|
||||
}
|
||||
t.controlBuf = newControlBuffer(t.ctxDone)
|
||||
if opts.InitialWindowSize >= defaultWindowSize {
|
||||
|
|
@ -259,6 +275,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne
|
|||
// a dedicated goroutine which reads HTTP2 frame from network. Then it
|
||||
// dispatches the frame to the corresponding stream entity.
|
||||
go t.reader()
|
||||
|
||||
// Send connection preface to server.
|
||||
n, err := t.conn.Write(clientPreface)
|
||||
if err != nil {
|
||||
|
|
@ -295,6 +312,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne
|
|||
return nil, connectionErrorf(true, err, "transport: failed to write window update: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
t.framer.writer.Flush()
|
||||
go func() {
|
||||
t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst)
|
||||
|
|
@ -443,7 +461,7 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
|
|||
|
||||
func (t *http2Client) createAudience(callHdr *CallHdr) string {
|
||||
// Create an audience string only if needed.
|
||||
if len(t.creds) == 0 && callHdr.Creds == nil {
|
||||
if len(t.perRPCCreds) == 0 && callHdr.Creds == nil {
|
||||
return ""
|
||||
}
|
||||
// Construct URI required to get auth request metadata.
|
||||
|
|
@ -458,7 +476,7 @@ func (t *http2Client) createAudience(callHdr *CallHdr) string {
|
|||
|
||||
func (t *http2Client) getTrAuthData(ctx context.Context, audience string) (map[string]string, error) {
|
||||
authData := map[string]string{}
|
||||
for _, c := range t.creds {
|
||||
for _, c := range t.perRPCCreds {
|
||||
data, err := c.GetRequestMetadata(ctx, audience)
|
||||
if err != nil {
|
||||
if _, ok := status.FromError(err); ok {
|
||||
|
|
@ -664,7 +682,9 @@ func (t *http2Client) CloseStream(s *Stream, err error) {
|
|||
func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.ErrCode, st *status.Status, mdata map[string][]string, eosReceived bool) {
|
||||
// Set stream status to done.
|
||||
if s.swapState(streamDone) == streamDone {
|
||||
// If it was already done, return.
|
||||
// If it was already done, return. If multiple closeStream calls
|
||||
// happen simultaneously, wait for the first to finish.
|
||||
<-s.done
|
||||
return
|
||||
}
|
||||
// status and trailers can be updated here without any synchronization because the stream goroutine will
|
||||
|
|
@ -678,8 +698,6 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.
|
|||
// This will unblock reads eventually.
|
||||
s.write(recvMsg{err: err})
|
||||
}
|
||||
// This will unblock write.
|
||||
close(s.done)
|
||||
// If headerChan isn't closed, then close it.
|
||||
if atomic.SwapUint32(&s.headerDone, 1) == 0 {
|
||||
s.noHeaders = true
|
||||
|
|
@ -715,11 +733,17 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.
|
|||
return true
|
||||
}
|
||||
t.controlBuf.executeAndPut(addBackStreamQuota, cleanup)
|
||||
// This will unblock write.
|
||||
close(s.done)
|
||||
}
|
||||
|
||||
// Close kicks off the shutdown process of the transport. This should be called
|
||||
// only once on a transport. Once it is called, the transport should not be
|
||||
// accessed any more.
|
||||
//
|
||||
// This method blocks until the addrConn that initiated this transport is
|
||||
// re-connected. This happens because t.onClose() begins reconnect logic at the
|
||||
// addrConn level and blocks until the addrConn is successfully connected.
|
||||
func (t *http2Client) Close() error {
|
||||
t.mu.Lock()
|
||||
// Make sure we only Close once.
|
||||
|
|
@ -747,6 +771,7 @@ func (t *http2Client) Close() error {
|
|||
}
|
||||
t.statsHandler.HandleConn(t.ctx, connEnd)
|
||||
}
|
||||
go t.onClose()
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1043,6 +1068,9 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) {
|
|||
close(t.goAway)
|
||||
t.state = draining
|
||||
t.controlBuf.put(&incomingGoAway{})
|
||||
|
||||
// This has to be a new goroutine because we're still using the current goroutine to read in the transport.
|
||||
t.onGoAway(t.goAwayReason)
|
||||
}
|
||||
// All streams with IDs greater than the GoAwayId
|
||||
// and smaller than the previous GoAway ID should be killed.
|
||||
|
|
@ -1145,7 +1173,9 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
|
|||
if !endStream {
|
||||
return
|
||||
}
|
||||
t.closeStream(s, io.EOF, false, http2.ErrCodeNo, state.status(), state.mdata, true)
|
||||
// if client received END_STREAM from server while stream was still active, send RST_STREAM
|
||||
rst := s.getState() == streamActive
|
||||
t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, state.status(), state.mdata, true)
|
||||
}
|
||||
|
||||
// reader runs as a separate goroutine in charge of reading data from network
|
||||
|
|
@ -1159,15 +1189,16 @@ func (t *http2Client) reader() {
|
|||
// Check the validity of server preface.
|
||||
frame, err := t.framer.fr.ReadFrame()
|
||||
if err != nil {
|
||||
t.Close()
|
||||
t.Close() // this kicks off resetTransport, so must be last before return
|
||||
return
|
||||
}
|
||||
t.conn.SetReadDeadline(time.Time{}) // reset deadline once we get the settings frame (we didn't time out, yay!)
|
||||
if t.keepaliveEnabled {
|
||||
atomic.CompareAndSwapUint32(&t.activity, 0, 1)
|
||||
}
|
||||
sf, ok := frame.(*http2.SettingsFrame)
|
||||
if !ok {
|
||||
t.Close()
|
||||
t.Close() // this kicks off resetTransport, so must be last before return
|
||||
return
|
||||
}
|
||||
t.onSuccess()
|
||||
|
|
|
|||
10
vendor/google.golang.org/grpc/internal/transport/http_util.go
generated
vendored
10
vendor/google.golang.org/grpc/internal/transport/http_util.go
generated
vendored
|
|
@ -24,6 +24,7 @@ import (
|
|||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
|
@ -435,6 +436,10 @@ func decodeTimeout(s string) (time.Duration, error) {
|
|||
if size < 2 {
|
||||
return 0, fmt.Errorf("transport: timeout string is too short: %q", s)
|
||||
}
|
||||
if size > 9 {
|
||||
// Spec allows for 8 digits plus the unit.
|
||||
return 0, fmt.Errorf("transport: timeout string is too long: %q", s)
|
||||
}
|
||||
unit := timeoutUnit(s[size-1])
|
||||
d, ok := timeoutUnitToDuration(unit)
|
||||
if !ok {
|
||||
|
|
@ -444,6 +449,11 @@ func decodeTimeout(s string) (time.Duration, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
const maxHours = math.MaxInt64 / int64(time.Hour)
|
||||
if d == time.Hour && t > maxHours {
|
||||
// This timeout would overflow math.MaxInt64; clamp it.
|
||||
return time.Duration(math.MaxInt64), nil
|
||||
}
|
||||
return d * time.Duration(t), nil
|
||||
}
|
||||
|
||||
|
|
|
|||
10
vendor/google.golang.org/grpc/internal/transport/transport.go
generated
vendored
10
vendor/google.golang.org/grpc/internal/transport/transport.go
generated
vendored
|
|
@ -465,8 +465,12 @@ type ConnectOptions struct {
|
|||
FailOnNonTempDialError bool
|
||||
// PerRPCCredentials stores the PerRPCCredentials required to issue RPCs.
|
||||
PerRPCCredentials []credentials.PerRPCCredentials
|
||||
// TransportCredentials stores the Authenticator required to setup a client connection.
|
||||
// TransportCredentials stores the Authenticator required to setup a client
|
||||
// connection. Only one of TransportCredentials and CredsBundle is non-nil.
|
||||
TransportCredentials credentials.TransportCredentials
|
||||
// CredsBundle is the credentials bundle to be used. Only one of
|
||||
// TransportCredentials and CredsBundle is non-nil.
|
||||
CredsBundle credentials.Bundle
|
||||
// KeepaliveParams stores the keepalive parameters.
|
||||
KeepaliveParams keepalive.ClientParameters
|
||||
// StatsHandler stores the handler for stats.
|
||||
|
|
@ -494,8 +498,8 @@ type TargetInfo struct {
|
|||
|
||||
// NewClientTransport establishes the transport with the required ConnectOptions
|
||||
// and returns it to the caller.
|
||||
func NewClientTransport(connectCtx, ctx context.Context, target TargetInfo, opts ConnectOptions, onSuccess func()) (ClientTransport, error) {
|
||||
return newHTTP2Client(connectCtx, ctx, target, opts, onSuccess)
|
||||
func NewClientTransport(connectCtx, ctx context.Context, target TargetInfo, opts ConnectOptions, onSuccess func(), onGoAway func(GoAwayReason), onClose func()) (ClientTransport, error) {
|
||||
return newHTTP2Client(connectCtx, ctx, target, opts, onSuccess, onGoAway, onClose)
|
||||
}
|
||||
|
||||
// Options provides additional hints and information for message
|
||||
|
|
|
|||
62
vendor/google.golang.org/grpc/keepalive/keepalive.go
generated
vendored
62
vendor/google.golang.org/grpc/keepalive/keepalive.go
generated
vendored
|
|
@ -16,7 +16,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// Package keepalive defines configurable parameters for point-to-point healthcheck.
|
||||
// Package keepalive defines configurable parameters for point-to-point
|
||||
// healthcheck.
|
||||
package keepalive
|
||||
|
||||
import (
|
||||
|
|
@ -24,42 +25,59 @@ import (
|
|||
)
|
||||
|
||||
// ClientParameters is used to set keepalive parameters on the client-side.
|
||||
// These configure how the client will actively probe to notice when a connection is broken
|
||||
// and send pings so intermediaries will be aware of the liveness of the connection.
|
||||
// Make sure these parameters are set in coordination with the keepalive policy on the server,
|
||||
// as incompatible settings can result in closing of connection.
|
||||
// These configure how the client will actively probe to notice when a
|
||||
// connection is broken and send pings so intermediaries will be aware of the
|
||||
// liveness of the connection. Make sure these parameters are set in
|
||||
// coordination with the keepalive policy on the server, as incompatible
|
||||
// settings can result in closing of connection.
|
||||
type ClientParameters struct {
|
||||
// After a duration of this time if the client doesn't see any activity it pings the server to see if the transport is still alive.
|
||||
// After a duration of this time if the client doesn't see any activity it
|
||||
// pings the server to see if the transport is still alive.
|
||||
Time time.Duration // The current default value is infinity.
|
||||
// After having pinged for keepalive check, the client waits for a duration of Timeout and if no activity is seen even after that
|
||||
// the connection is closed.
|
||||
// After having pinged for keepalive check, the client waits for a duration
|
||||
// of Timeout and if no activity is seen even after that the connection is
|
||||
// closed.
|
||||
Timeout time.Duration // The current default value is 20 seconds.
|
||||
// If true, client runs keepalive checks even with no active RPCs.
|
||||
// If true, client sends keepalive pings even with no active RPCs. If false,
|
||||
// when there are no active RPCs, Time and Timeout will be ignored and no
|
||||
// keepalive pings will be sent.
|
||||
PermitWithoutStream bool // false by default.
|
||||
}
|
||||
|
||||
// ServerParameters is used to set keepalive and max-age parameters on the server-side.
|
||||
// ServerParameters is used to set keepalive and max-age parameters on the
|
||||
// server-side.
|
||||
type ServerParameters struct {
|
||||
// MaxConnectionIdle is a duration for the amount of time after which an idle connection would be closed by sending a GoAway.
|
||||
// Idleness duration is defined since the most recent time the number of outstanding RPCs became zero or the connection establishment.
|
||||
// MaxConnectionIdle is a duration for the amount of time after which an
|
||||
// idle connection would be closed by sending a GoAway. Idleness duration is
|
||||
// defined since the most recent time the number of outstanding RPCs became
|
||||
// zero or the connection establishment.
|
||||
MaxConnectionIdle time.Duration // The current default value is infinity.
|
||||
// MaxConnectionAge is a duration for the maximum amount of time a connection may exist before it will be closed by sending a GoAway.
|
||||
// A random jitter of +/-10% will be added to MaxConnectionAge to spread out connection storms.
|
||||
// MaxConnectionAge is a duration for the maximum amount of time a
|
||||
// connection may exist before it will be closed by sending a GoAway. A
|
||||
// random jitter of +/-10% will be added to MaxConnectionAge to spread out
|
||||
// connection storms.
|
||||
MaxConnectionAge time.Duration // The current default value is infinity.
|
||||
// MaxConnectinoAgeGrace is an additive period after MaxConnectionAge after which the connection will be forcibly closed.
|
||||
// MaxConnectinoAgeGrace is an additive period after MaxConnectionAge after
|
||||
// which the connection will be forcibly closed.
|
||||
MaxConnectionAgeGrace time.Duration // The current default value is infinity.
|
||||
// After a duration of this time if the server doesn't see any activity it pings the client to see if the transport is still alive.
|
||||
// After a duration of this time if the server doesn't see any activity it
|
||||
// pings the client to see if the transport is still alive.
|
||||
Time time.Duration // The current default value is 2 hours.
|
||||
// After having pinged for keepalive check, the server waits for a duration of Timeout and if no activity is seen even after that
|
||||
// the connection is closed.
|
||||
// After having pinged for keepalive check, the server waits for a duration
|
||||
// of Timeout and if no activity is seen even after that the connection is
|
||||
// closed.
|
||||
Timeout time.Duration // The current default value is 20 seconds.
|
||||
}
|
||||
|
||||
// EnforcementPolicy is used to set keepalive enforcement policy on the server-side.
|
||||
// Server will close connection with a client that violates this policy.
|
||||
// EnforcementPolicy is used to set keepalive enforcement policy on the
|
||||
// server-side. Server will close connection with a client that violates this
|
||||
// policy.
|
||||
type EnforcementPolicy struct {
|
||||
// MinTime is the minimum amount of time a client should wait before sending a keepalive ping.
|
||||
// MinTime is the minimum amount of time a client should wait before sending
|
||||
// a keepalive ping.
|
||||
MinTime time.Duration // The current default value is 5 minutes.
|
||||
// If true, server expects keepalive pings even when there are no active streams(RPCs).
|
||||
// If true, server allows keepalive pings even when there are no active
|
||||
// streams(RPCs). If false, and client sends ping when there are no active
|
||||
// streams, server will send GOAWAY and close the connection.
|
||||
PermitWithoutStream bool // false by default.
|
||||
}
|
||||
|
|
|
|||
1
vendor/google.golang.org/grpc/pickfirst.go
generated
vendored
1
vendor/google.golang.org/grpc/pickfirst.go
generated
vendored
|
|
@ -56,6 +56,7 @@ func (b *pickfirstBalancer) HandleResolvedAddrs(addrs []resolver.Address, err er
|
|||
if b.sc == nil {
|
||||
b.sc, err = b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{})
|
||||
if err != nil {
|
||||
//TODO(yuxuanli): why not change the cc state to Idle?
|
||||
grpclog.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
43
vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go
generated
vendored
43
vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go
generated
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2017 gRPC authors.
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -73,10 +73,7 @@ type dnsBuilder struct {
|
|||
|
||||
// Build creates and starts a DNS resolver that watches the name resolution of the target.
|
||||
func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOption) (resolver.Resolver, error) {
|
||||
if target.Authority != "" {
|
||||
return nil, fmt.Errorf("default DNS resolver does not support custom DNS server")
|
||||
}
|
||||
host, port, err := parseTarget(target.Endpoint)
|
||||
host, port, err := parseTarget(target.Endpoint, defaultPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -111,6 +108,15 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts
|
|||
disableServiceConfig: opts.DisableServiceConfig,
|
||||
}
|
||||
|
||||
if target.Authority == "" {
|
||||
d.resolver = defaultResolver
|
||||
} else {
|
||||
d.resolver, err = customAuthorityResolver(target.Authority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d.wg.Add(1)
|
||||
go d.watcher()
|
||||
return d, nil
|
||||
|
|
@ -121,6 +127,12 @@ func (b *dnsBuilder) Scheme() string {
|
|||
return "dns"
|
||||
}
|
||||
|
||||
type netResolver interface {
|
||||
LookupHost(ctx context.Context, host string) (addrs []string, err error)
|
||||
LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)
|
||||
LookupTXT(ctx context.Context, name string) (txts []string, err error)
|
||||
}
|
||||
|
||||
// ipResolver watches for the name resolution update for an IP address.
|
||||
type ipResolver struct {
|
||||
cc resolver.ClientConn
|
||||
|
|
@ -161,6 +173,7 @@ type dnsResolver struct {
|
|||
retryCount int
|
||||
host string
|
||||
port string
|
||||
resolver netResolver
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
cc resolver.ClientConn
|
||||
|
|
@ -218,13 +231,13 @@ func (d *dnsResolver) watcher() {
|
|||
|
||||
func (d *dnsResolver) lookupSRV() []resolver.Address {
|
||||
var newAddrs []resolver.Address
|
||||
_, srvs, err := lookupSRV(d.ctx, "grpclb", "tcp", d.host)
|
||||
_, srvs, err := d.resolver.LookupSRV(d.ctx, "grpclb", "tcp", d.host)
|
||||
if err != nil {
|
||||
grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err)
|
||||
return nil
|
||||
}
|
||||
for _, s := range srvs {
|
||||
lbAddrs, err := lookupHost(d.ctx, s.Target)
|
||||
lbAddrs, err := d.resolver.LookupHost(d.ctx, s.Target)
|
||||
if err != nil {
|
||||
grpclog.Infof("grpc: failed load balancer address dns lookup due to %v.\n", err)
|
||||
continue
|
||||
|
|
@ -243,7 +256,7 @@ func (d *dnsResolver) lookupSRV() []resolver.Address {
|
|||
}
|
||||
|
||||
func (d *dnsResolver) lookupTXT() string {
|
||||
ss, err := lookupTXT(d.ctx, d.host)
|
||||
ss, err := d.resolver.LookupTXT(d.ctx, d.host)
|
||||
if err != nil {
|
||||
grpclog.Infof("grpc: failed dns TXT record lookup due to %v.\n", err)
|
||||
return ""
|
||||
|
|
@ -263,7 +276,7 @@ func (d *dnsResolver) lookupTXT() string {
|
|||
|
||||
func (d *dnsResolver) lookupHost() []resolver.Address {
|
||||
var newAddrs []resolver.Address
|
||||
addrs, err := lookupHost(d.ctx, d.host)
|
||||
addrs, err := d.resolver.LookupHost(d.ctx, d.host)
|
||||
if err != nil {
|
||||
grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err)
|
||||
return nil
|
||||
|
|
@ -305,16 +318,16 @@ func formatIP(addr string) (addrIP string, ok bool) {
|
|||
return "[" + addr + "]", true
|
||||
}
|
||||
|
||||
// parseTarget takes the user input target string, returns formatted host and port info.
|
||||
// parseTarget takes the user input target string and default port, returns formatted host and port info.
|
||||
// If target doesn't specify a port, set the port to be the defaultPort.
|
||||
// If target is in IPv6 format and host-name is enclosed in sqarue brackets, brackets
|
||||
// are strippd when setting the host.
|
||||
// examples:
|
||||
// target: "www.google.com" returns host: "www.google.com", port: "443"
|
||||
// target: "ipv4-host:80" returns host: "ipv4-host", port: "80"
|
||||
// target: "[ipv6-host]" returns host: "ipv6-host", port: "443"
|
||||
// target: ":80" returns host: "localhost", port: "80"
|
||||
func parseTarget(target string) (host, port string, err error) {
|
||||
// target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443"
|
||||
// target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80"
|
||||
// target: "[ipv6-host]" defaultPort: "443" returns host: "ipv6-host", port: "443"
|
||||
// target: ":80" defaultPort: "443" returns host: "localhost", port: "80"
|
||||
func parseTarget(target, defaultPort string) (host, port string, err error) {
|
||||
if target == "" {
|
||||
return "", "", errMissingAddr
|
||||
}
|
||||
|
|
|
|||
35
vendor/google.golang.org/grpc/resolver/dns/go17.go
generated
vendored
35
vendor/google.golang.org/grpc/resolver/dns/go17.go
generated
vendored
|
|
@ -1,35 +0,0 @@
|
|||
// +build go1.6, !go1.8
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright 2017 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
lookupHost = func(ctx context.Context, host string) ([]string, error) { return net.LookupHost(host) }
|
||||
lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) {
|
||||
return net.LookupSRV(service, proto, name)
|
||||
}
|
||||
lookupTXT = func(ctx context.Context, name string) ([]string, error) { return net.LookupTXT(name) }
|
||||
)
|
||||
29
vendor/google.golang.org/grpc/resolver/dns/go18.go
generated
vendored
29
vendor/google.golang.org/grpc/resolver/dns/go18.go
generated
vendored
|
|
@ -1,29 +0,0 @@
|
|||
// +build go1.8
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright 2017 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package dns
|
||||
|
||||
import "net"
|
||||
|
||||
var (
|
||||
lookupHost = net.DefaultResolver.LookupHost
|
||||
lookupSRV = net.DefaultResolver.LookupSRV
|
||||
lookupTXT = net.DefaultResolver.LookupTXT
|
||||
)
|
||||
54
vendor/google.golang.org/grpc/resolver/dns/go19.go
generated
vendored
Normal file
54
vendor/google.golang.org/grpc/resolver/dns/go19.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// +build go1.9
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultResolver netResolver = net.DefaultResolver
|
||||
)
|
||||
|
||||
const defaultDNSSvrPort = "53"
|
||||
|
||||
var customAuthorityDialler = func(authority string) func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
var dialer net.Dialer
|
||||
return dialer.DialContext(ctx, network, authority)
|
||||
}
|
||||
}
|
||||
|
||||
var customAuthorityResolver = func(authority string) (netResolver, error) {
|
||||
host, port, err := parseTarget(authority, defaultDNSSvrPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authorityWithPort := net.JoinHostPort(host, port)
|
||||
|
||||
return &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: customAuthorityDialler(authorityWithPort),
|
||||
}, nil
|
||||
}
|
||||
51
vendor/google.golang.org/grpc/resolver/dns/pre_go19.go
generated
vendored
Normal file
51
vendor/google.golang.org/grpc/resolver/dns/pre_go19.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// +build go1.6, !go1.9
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultResolver netResolver = &preGo19Resolver{}
|
||||
)
|
||||
|
||||
type preGo19Resolver struct {
|
||||
}
|
||||
|
||||
func (*preGo19Resolver) LookupHost(ctx context.Context, host string) ([]string, error) {
|
||||
return net.LookupHost(host)
|
||||
}
|
||||
|
||||
func (*preGo19Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) {
|
||||
return net.LookupSRV(service, proto, name)
|
||||
}
|
||||
|
||||
func (*preGo19Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
|
||||
return net.LookupTXT(name)
|
||||
}
|
||||
|
||||
var customAuthorityResolver = func(authority string) (netResolver, error) {
|
||||
return nil, fmt.Errorf("Default DNS resolver does not support custom DNS server with go < 1.9")
|
||||
}
|
||||
41
vendor/google.golang.org/grpc/resolver_conn_wrapper.go
generated
vendored
41
vendor/google.golang.org/grpc/resolver_conn_wrapper.go
generated
vendored
|
|
@ -23,17 +23,19 @@ import (
|
|||
"strings"
|
||||
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/internal/channelz"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
// ccResolverWrapper is a wrapper on top of cc for resolvers.
|
||||
// It implements resolver.ClientConnection interface.
|
||||
type ccResolverWrapper struct {
|
||||
cc *ClientConn
|
||||
resolver resolver.Resolver
|
||||
addrCh chan []resolver.Address
|
||||
scCh chan string
|
||||
done chan struct{}
|
||||
cc *ClientConn
|
||||
resolver resolver.Resolver
|
||||
addrCh chan []resolver.Address
|
||||
scCh chan string
|
||||
done chan struct{}
|
||||
lastAddressesCount int
|
||||
}
|
||||
|
||||
// split2 returns the values from strings.SplitN(s, sep, 2).
|
||||
|
|
@ -114,6 +116,9 @@ func (ccr *ccResolverWrapper) watcher() {
|
|||
default:
|
||||
}
|
||||
grpclog.Infof("ccResolverWrapper: sending new addresses to cc: %v", addrs)
|
||||
if channelz.IsOn() {
|
||||
ccr.addChannelzTraceEvent(addrs)
|
||||
}
|
||||
ccr.cc.handleResolvedAddrs(addrs, nil)
|
||||
case sc := <-ccr.scCh:
|
||||
select {
|
||||
|
|
@ -156,3 +161,29 @@ func (ccr *ccResolverWrapper) NewServiceConfig(sc string) {
|
|||
}
|
||||
ccr.scCh <- sc
|
||||
}
|
||||
|
||||
func (ccr *ccResolverWrapper) addChannelzTraceEvent(addrs []resolver.Address) {
|
||||
if len(addrs) == 0 && ccr.lastAddressesCount != 0 {
|
||||
channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: "Resolver returns an empty address list",
|
||||
Severity: channelz.CtWarning,
|
||||
})
|
||||
} else if len(addrs) != 0 && ccr.lastAddressesCount == 0 {
|
||||
var s string
|
||||
for i, a := range addrs {
|
||||
if a.ServerName != "" {
|
||||
s += a.Addr + "(" + a.ServerName + ")"
|
||||
} else {
|
||||
s += a.Addr
|
||||
}
|
||||
if i != len(addrs)-1 {
|
||||
s += " "
|
||||
}
|
||||
}
|
||||
channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{
|
||||
Desc: fmt.Sprintf("Resolver returns a non-empty address list (previous one was empty) %q", s),
|
||||
Severity: channelz.CtINFO,
|
||||
})
|
||||
}
|
||||
ccr.lastAddressesCount = len(addrs)
|
||||
}
|
||||
|
|
|
|||
33
vendor/google.golang.org/grpc/rpc_util.go
generated
vendored
33
vendor/google.golang.org/grpc/rpc_util.go
generated
vendored
|
|
@ -531,7 +531,10 @@ func compress(in []byte, cp Compressor, compressor encoding.Compressor) ([]byte,
|
|||
}
|
||||
cbuf := &bytes.Buffer{}
|
||||
if compressor != nil {
|
||||
z, _ := compressor.Compress(cbuf)
|
||||
z, err := compressor.Compress(cbuf)
|
||||
if err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
if _, err := z.Write(in); err != nil {
|
||||
return nil, wrapErr(err)
|
||||
}
|
||||
|
|
@ -595,20 +598,17 @@ func checkRecvPayload(pf payloadFormat, recvCompress string, haveCompressor bool
|
|||
return nil
|
||||
}
|
||||
|
||||
// For the two compressor parameters, both should not be set, but if they are,
|
||||
// dc takes precedence over compressor.
|
||||
// TODO(dfawley): wrap the old compressor/decompressor using the new API?
|
||||
func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, inPayload *stats.InPayload, compressor encoding.Compressor) error {
|
||||
func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxReceiveMessageSize int, inPayload *stats.InPayload, compressor encoding.Compressor) ([]byte, error) {
|
||||
pf, d, err := p.recvMsg(maxReceiveMessageSize)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if inPayload != nil {
|
||||
inPayload.WireLength = len(d)
|
||||
}
|
||||
|
||||
if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil); st != nil {
|
||||
return st.Err()
|
||||
return nil, st.Err()
|
||||
}
|
||||
|
||||
if pf == compressionMade {
|
||||
|
|
@ -617,23 +617,34 @@ func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interf
|
|||
if dc != nil {
|
||||
d, err = dc.Do(bytes.NewReader(d))
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
}
|
||||
} else {
|
||||
dcReader, err := compressor.Decompress(bytes.NewReader(d))
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
}
|
||||
d, err = ioutil.ReadAll(dcReader)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(d) > maxReceiveMessageSize {
|
||||
// TODO: Revisit the error code. Currently keep it consistent with java
|
||||
// implementation.
|
||||
return status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(d), maxReceiveMessageSize)
|
||||
return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(d), maxReceiveMessageSize)
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// For the two compressor parameters, both should not be set, but if they are,
|
||||
// dc takes precedence over compressor.
|
||||
// TODO(dfawley): wrap the old compressor/decompressor using the new API?
|
||||
func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, inPayload *stats.InPayload, compressor encoding.Compressor) error {
|
||||
d, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, inPayload, compressor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Unmarshal(d, m); err != nil {
|
||||
return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message %v", err)
|
||||
|
|
|
|||
111
vendor/google.golang.org/grpc/server.go
generated
vendored
111
vendor/google.golang.org/grpc/server.go
generated
vendored
|
|
@ -19,7 +19,6 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -33,8 +32,6 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/trace"
|
||||
|
||||
|
|
@ -901,76 +898,32 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
|
|||
}
|
||||
}
|
||||
|
||||
p := &parser{r: stream}
|
||||
pf, req, err := p.recvMsg(s.opts.maxReceiveMessageSize)
|
||||
if err == io.EOF {
|
||||
// The entire stream is done (for unary RPC only).
|
||||
return err
|
||||
}
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
err = status.Errorf(codes.Internal, io.ErrUnexpectedEOF.Error())
|
||||
var inPayload *stats.InPayload
|
||||
if sh != nil {
|
||||
inPayload = &stats.InPayload{
|
||||
RecvTime: time.Now(),
|
||||
}
|
||||
}
|
||||
d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, inPayload, decomp)
|
||||
if err != nil {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
if e := t.WriteStatus(stream, st); e != nil {
|
||||
grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e)
|
||||
}
|
||||
} else {
|
||||
switch st := err.(type) {
|
||||
case transport.ConnectionError:
|
||||
// Nothing to do here.
|
||||
default:
|
||||
panic(fmt.Sprintf("grpc: Unexpected error (%T) from recvMsg: %v", st, st))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
t.IncrMsgRecv()
|
||||
}
|
||||
if st := checkRecvPayload(pf, stream.RecvCompress(), dc != nil || decomp != nil); st != nil {
|
||||
if e := t.WriteStatus(stream, st); e != nil {
|
||||
grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e)
|
||||
}
|
||||
return st.Err()
|
||||
}
|
||||
var inPayload *stats.InPayload
|
||||
if sh != nil {
|
||||
inPayload = &stats.InPayload{
|
||||
RecvTime: time.Now(),
|
||||
}
|
||||
}
|
||||
df := func(v interface{}) error {
|
||||
if inPayload != nil {
|
||||
inPayload.WireLength = len(req)
|
||||
}
|
||||
if pf == compressionMade {
|
||||
var err error
|
||||
if dc != nil {
|
||||
req, err = dc.Do(bytes.NewReader(req))
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, err.Error())
|
||||
}
|
||||
} else {
|
||||
tmp, _ := decomp.Decompress(bytes.NewReader(req))
|
||||
req, err = ioutil.ReadAll(tmp)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(req) > s.opts.maxReceiveMessageSize {
|
||||
// TODO: Revisit the error code. Currently keep it consistent with
|
||||
// java implementation.
|
||||
return status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(req), s.opts.maxReceiveMessageSize)
|
||||
}
|
||||
if err := s.getCodec(stream.ContentSubtype()).Unmarshal(req, v); err != nil {
|
||||
if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil {
|
||||
return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err)
|
||||
}
|
||||
if inPayload != nil {
|
||||
inPayload.Payload = v
|
||||
inPayload.Data = req
|
||||
inPayload.Length = len(req)
|
||||
inPayload.Data = d
|
||||
inPayload.Length = len(d)
|
||||
sh.HandleRPC(stream.Context(), inPayload)
|
||||
}
|
||||
if trInfo != nil {
|
||||
|
|
@ -1180,47 +1133,27 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str
|
|||
}
|
||||
service := sm[:pos]
|
||||
method := sm[pos+1:]
|
||||
srv, ok := s.m[service]
|
||||
if !ok {
|
||||
if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil {
|
||||
s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo)
|
||||
|
||||
if srv, ok := s.m[service]; ok {
|
||||
if md, ok := srv.md[method]; ok {
|
||||
s.processUnaryRPC(t, stream, srv, md, trInfo)
|
||||
return
|
||||
}
|
||||
if trInfo != nil {
|
||||
trInfo.tr.LazyLog(&fmtStringer{"Unknown service %v", []interface{}{service}}, true)
|
||||
trInfo.tr.SetError()
|
||||
if sd, ok := srv.sd[method]; ok {
|
||||
s.processStreamingRPC(t, stream, srv, sd, trInfo)
|
||||
return
|
||||
}
|
||||
errDesc := fmt.Sprintf("unknown service %v", service)
|
||||
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
|
||||
if trInfo != nil {
|
||||
trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
|
||||
trInfo.tr.SetError()
|
||||
}
|
||||
grpclog.Warningf("grpc: Server.handleStream failed to write status: %v", err)
|
||||
}
|
||||
if trInfo != nil {
|
||||
trInfo.tr.Finish()
|
||||
}
|
||||
return
|
||||
}
|
||||
// Unary RPC or Streaming RPC?
|
||||
if md, ok := srv.md[method]; ok {
|
||||
s.processUnaryRPC(t, stream, srv, md, trInfo)
|
||||
return
|
||||
}
|
||||
if sd, ok := srv.sd[method]; ok {
|
||||
s.processStreamingRPC(t, stream, srv, sd, trInfo)
|
||||
return
|
||||
}
|
||||
if trInfo != nil {
|
||||
trInfo.tr.LazyLog(&fmtStringer{"Unknown method %v", []interface{}{method}}, true)
|
||||
trInfo.tr.SetError()
|
||||
}
|
||||
// Unknown service, or known server unknown method.
|
||||
if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil {
|
||||
s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo)
|
||||
return
|
||||
}
|
||||
errDesc := fmt.Sprintf("unknown method %v", method)
|
||||
if trInfo != nil {
|
||||
trInfo.tr.LazyLog(&fmtStringer{"Unknown service %v", []interface{}{service}}, true)
|
||||
trInfo.tr.SetError()
|
||||
}
|
||||
errDesc := fmt.Sprintf("unknown service %v", service)
|
||||
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
|
||||
if trInfo != nil {
|
||||
trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
|
||||
|
|
|
|||
3
vendor/google.golang.org/grpc/service_config.go
generated
vendored
3
vendor/google.golang.org/grpc/service_config.go
generated
vendored
|
|
@ -229,6 +229,9 @@ type jsonSC struct {
|
|||
}
|
||||
|
||||
func parseServiceConfig(js string) (ServiceConfig, error) {
|
||||
if len(js) == 0 {
|
||||
return ServiceConfig{}, fmt.Errorf("no JSON service config provided")
|
||||
}
|
||||
var rsc jsonSC
|
||||
err := json.Unmarshal([]byte(js), &rsc)
|
||||
if err != nil {
|
||||
|
|
|
|||
8
vendor/google.golang.org/grpc/status/status.go
generated
vendored
8
vendor/google.golang.org/grpc/status/status.go
generated
vendored
|
|
@ -126,7 +126,9 @@ func FromError(err error) (s *Status, ok bool) {
|
|||
if err == nil {
|
||||
return &Status{s: &spb.Status{Code: int32(codes.OK)}}, true
|
||||
}
|
||||
if se, ok := err.(interface{ GRPCStatus() *Status }); ok {
|
||||
if se, ok := err.(interface {
|
||||
GRPCStatus() *Status
|
||||
}); ok {
|
||||
return se.GRPCStatus(), true
|
||||
}
|
||||
return New(codes.Unknown, err.Error()), false
|
||||
|
|
@ -182,7 +184,9 @@ func Code(err error) codes.Code {
|
|||
if err == nil {
|
||||
return codes.OK
|
||||
}
|
||||
if se, ok := err.(interface{ GRPCStatus() *Status }); ok {
|
||||
if se, ok := err.(interface {
|
||||
GRPCStatus() *Status
|
||||
}); ok {
|
||||
return se.GRPCStatus().Code()
|
||||
}
|
||||
return codes.Unknown
|
||||
|
|
|
|||
12
vendor/google.golang.org/grpc/stream.go
generated
vendored
12
vendor/google.golang.org/grpc/stream.go
generated
vendored
|
|
@ -660,7 +660,14 @@ func (cs *clientStream) CloseSend() error {
|
|||
return nil
|
||||
}
|
||||
cs.sentLast = true
|
||||
op := func(a *csAttempt) error { return a.t.Write(a.s, nil, nil, &transport.Options{Last: true}) }
|
||||
op := func(a *csAttempt) error {
|
||||
a.t.Write(a.s, nil, nil, &transport.Options{Last: true})
|
||||
// Always return nil; io.EOF is the only error that might make sense
|
||||
// instead, but there is no need to signal the client to call RecvMsg
|
||||
// as the only use left for the stream after CloseSend is to call
|
||||
// RecvMsg. This also matches historical behavior.
|
||||
return nil
|
||||
}
|
||||
cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) })
|
||||
// We never returned an error here for reasons.
|
||||
return nil
|
||||
|
|
@ -809,11 +816,14 @@ func (a *csAttempt) finish(err error) {
|
|||
|
||||
if a.done != nil {
|
||||
br := false
|
||||
var tr metadata.MD
|
||||
if a.s != nil {
|
||||
br = a.s.BytesReceived()
|
||||
tr = a.s.Trailer()
|
||||
}
|
||||
a.done(balancer.DoneInfo{
|
||||
Err: err,
|
||||
Trailer: tr,
|
||||
BytesSent: a.s != nil,
|
||||
BytesReceived: br,
|
||||
})
|
||||
|
|
|
|||
2
vendor/google.golang.org/grpc/version.go
generated
vendored
2
vendor/google.golang.org/grpc/version.go
generated
vendored
|
|
@ -19,4 +19,4 @@
|
|||
package grpc
|
||||
|
||||
// Version is the current grpc version.
|
||||
const Version = "1.15.0"
|
||||
const Version = "1.16.0"
|
||||
|
|
|
|||
11
vendor/google.golang.org/grpc/vet.sh
generated
vendored
11
vendor/google.golang.org/grpc/vet.sh
generated
vendored
|
|
@ -71,7 +71,7 @@ fi
|
|||
|
||||
git ls-files "*.go" | xargs grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" 2>&1 | tee /dev/stderr | (! read)
|
||||
git ls-files "*.go" | xargs grep -l '"math/rand"' 2>&1 | (! grep -v '^examples\|^stress\|grpcrand') | tee /dev/stderr | (! read)
|
||||
git ls-files | xargs dirname | sort | uniq | xargs go run go_vet/vet.go | tee /dev/stderr | (! read)
|
||||
git ls-files | xargs dirname | sort | uniq | xargs go run test/go_vet/vet.go | tee /dev/stderr | (! read)
|
||||
gofmt -s -d -l . 2>&1 | tee /dev/stderr | (! read)
|
||||
goimports -l . 2>&1 | tee /dev/stderr | (! read)
|
||||
golint ./... 2>&1 | (grep -vE "(_mock|\.pb)\.go:" || true) | tee /dev/stderr | (! read)
|
||||
|
|
@ -80,7 +80,14 @@ golint ./... 2>&1 | (grep -vE "(_mock|\.pb)\.go:" || true) | tee /dev/stderr | (
|
|||
# TODO: Remove this mangling once "context" is imported directly (grpc/grpc-go#711).
|
||||
git ls-files "*.go" | xargs sed -i 's:"golang.org/x/net/context":"context":'
|
||||
set +o pipefail # vet exits with non-zero error if issues are found
|
||||
go tool vet -all . 2>&1 | grep -vE 'clientconn.go:.*cancel (function|var)' | tee /dev/stderr | (! read)
|
||||
|
||||
# TODO(deklerk) remove when we drop Go 1.6 support
|
||||
go tool vet -all . 2>&1 | \
|
||||
grep -vE 'clientconn.go:.*cancel (function|var)' | \
|
||||
grep -vE '.*transport_test.go:.*cancel' | \
|
||||
tee /dev/stderr | \
|
||||
(! read)
|
||||
|
||||
set -o pipefail
|
||||
git reset --hard HEAD
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue