Documentation ¶
Overview ¶
Package tenant encapsulates the logic and protocol-level details for managing tenant sub-processes.
Background:
In the interest of reducing the blast radius of bugs in the core query execution assembly code, we're executing queries in separate subprocesses, one for each "tenant." This ought to keep an out-of-bounds read bug from turning into cross-tenant information disclosure. However, we need to endure some unfortunate incidental complexity in order to make this strategy performant. In particular, we're trying our best to avoid having either one of the Go processes (or the kenel) from having to copy data back and forth between pipes, etc., since the query processing pipeline would like to consume as much of our memory bandwidth as we can give it.
In order to avoid copies, each of the tenant processes is launched (lazily!) with a unix control socket over which we can pass it output file descriptors. So, every request to execute a query will be passed over the control socket *along with* the file descriptor to which the query output should be written.
There are two sorts of requests that can be made to a tenant:
"Direct Execution" requests, which are produced by Mangager.Do, provide a query plan to a specific local tenant process, along with an output file descriptor for the tenant to write to. The tenant performs the query and writes the results to the file descriptor.
"Proxy Execution" requests, which are produced by tenant processes themselves, provide the ability for a tenant on one machine to "fan out" a query to multiple tenant processes across different machines. These are made available through Manager.Remote (see also: tnproto.Remote).
In practice, "split" query plans (ones that are meant to run on multiple machines) will use both of the request types above. The original ("reduction") query plan will be launched via a Direct Execution request, and then its constituent ("mapping") sub-queries will be requested by the tenant process via Proxy Execution requests.
Index ¶
Constants ¶
const DefaultCacheDir = "/tmp/tenant-cache"
const (
DefaultReapInterval = time.Hour
)
Variables ¶
var ErrOverloaded = errors.New("child overloaded")
ErrOverloaded can be returned by calls to Manager.Do when too many calls to Do are currently pending for the same tenant.
Functions ¶
func CanSandbox ¶
func CanSandbox() bool
CanSandbox returns whether or not tenants can be sandboxed using bwrap(1).
func Check ¶
func Check(rc io.ReadCloser, stats *plan.ExecStats) error
Check checks the return status of the tenant error pipe returned from Manager.Do. Check blocks until the other end of the pipe has been closed, and then closes this end of the pipe.
func DefaultEnv ¶
DefaultEnv is the default environment-generating function for the tenant process. The tenant process should not receive all of the parent's environment variables, as the parent may have credentials stored there.
The cache argument contains the return value of filepath.Join(CacheDir, id.String()) for the CacheDir configured in the manager (see Manager.CacheDir).
It sets the following:
PATH=$PATH SHELL=$SHELL HOME=$HOME LANG=C.UTF-8 CACHEDIR=<cache>
Types ¶
type Manager ¶
type Manager struct { // CacheDir is the root of the directory // tree used for caching data. CacheDir string // Sandbox determines if Manager // launches the tenant process // with bwrap(1) Sandbox bool // contains filtered or unexported fields }
Manager manages the state associated with multiple tenant processes. Manager can be used to talk to arbitrary tenant processes, and it takes care of lazily launching and killing tenant processes based on their utilization.
Broadly speaking, the tenant manager has two similar responsibilities:
- Allow *this* process to talk to a sub-process tenant directly.
- Allow other tenants inside other tenant managers to connect to the tenants running locally via Manager.Remote.
func NewManager ¶
NewManager makes a new Manager from the list of command-line arguments provided and the list of additional options.
The cmd list should contain at least one element, since the first element of the list indicates the name of the program to run.
func (*Manager) Do ¶
func (m *Manager) Do(id tnproto.ID, key tnproto.Key, t *plan.Tree, ofmt tnproto.OutputFormat, into net.Conn) (io.ReadCloser, error)
Do sends a DirectExec message to the given tenant ID managed by m. If the tenant process has not been started yet, it is launched lazily.
Do may return ErrOverloaded if many calls to Do for the same tenant ID are outstanding simultaneously. (The current implementation determines this by bailing out of acquisition of the child lock after 1 second of inactivity.)
Once Do returns, the query has begun execution. The returned io.ReadCloser will indicate when the query has completed execution and if any errors were encountered. (Use Check to block on query execution and check the final error status.)
The result of the query is executed into the socket backing the provided net.Conn. It is the caller's responsibility to close the provided connection. (Note that sending the socket over to the tenant subprocess involves creating a duplicated file handle, so closing 'into' immediately after a call to Do will not close the connection from the perspective of the tenant process.)
func (*Manager) Quit ¶
Quit sends a SIGQUIT to the tenant process with the provided ID. Quit returns true if the signal was sent successfully, or false if the signal could not be sent (either because no such tenant was running or because signal(2) failed).
type Option ¶
type Option func(m *Manager)
Option is an optional argument to NewManager to indicate optional Manager configuration.
func WithCgroup ¶
WithCgroup sets the delegated cgroup that the Manager will use to launch tenant processes. If the returned cgroup already exists, all the processes within it will be killed before spawning a new tenant process.
func WithGCInterval ¶
WithGCInterval is an option that can be passed to NewManager to indicate the desired process GC interval.
If interval is zero, then process GC is disabled.
func WithLogger ¶
WithLogger is an option that can be passed to NewManager to have it log diagnostic information and information from child subprocesses. If WithLogger is not provided, then the children share stdout and stderr with the parent process.
For child subprocesses, each line of output to stdout and stderr will be prefixed with the ID os the subprocess.
func WithRemote ¶
WithRemote is an option that can be passed to NewManager to indicate the listener on which to serve remote proxy exec messages.
Directories ¶
Path | Synopsis |
---|---|
Package dcache provides a cache for table data by storing files in a directory.
|
Package dcache provides a cache for table data by storing files in a directory. |
Package tnproto defines the types and functions necessary to speak the tenant control protocol.
|
Package tnproto defines the types and functions necessary to speak the tenant control protocol. |