snappyframed

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 28, 2014 License: MIT Imports: 8 Imported by: 0

README

snappyframed

Build Status GoDoc

This is a fork of the go-snappystream package. It has a cleaner interface and extra optimization.

This repository uses semantic versioning. If you want to protect yourself against backwards incompatible changes (of which no further are anticipated), you should the gopkg.in import path, "gopkg.in/bmatsuo/snappyframed.v1".

This package wraps snappy-go and supplies a Reader and Writer for the snappy framed stream format.

Documentation

Overview

Package snappyframed implements reading and writing of snappy framed compressed streams.

See the snappy repository for details on the framing format. https://snappy.googlecode.com/svn/trunk/framing_format.txt

Example (Pool)

This example shows how a sync.Pool might be used to speed up decoding and encoding of HTTP traffic. Depending on your application such an approach may not provide any benefit. Before making such a change it is important to instrument your system to measure performance gains.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"sync"

	snappyframed "."
)

// readerPool and writerPool are the simplest pool implementations for decoding
// and encoding snappyframed streams.  A real application may wish to wrap
// pools in a utility package that handles calling Get and Put on the pool
// transparently.
var readerPool = sync.Pool{New: func() interface{} { return snappyframed.NewReader(nil) }}
var writerPool = sync.Pool{New: func() interface{} { return snappyframed.NewWriter(nil) }}

// APIRequest is sent to the API in a JSON POST request.
type APIRequest struct {
	Name string
}

// APIResponse is sent to the API client in response to an APIRequest.
type APIResponse struct {
	Messages []string
}

// szAPIHandler reads a snappyframed stream encoding a JSON APIRequest and
// writes a JSON APIResponse encoded as a snappyframed stream.
func szAPIHandler(resp http.ResponseWriter, r *http.Request) {
	// decode the request entity as a snappy-framed stream.
	body := r.Body // it seems important not to reassign r.Body..
	defer body.Close()
	if r.Header.Get("Content-Type") == snappyframed.MediaType {
		// get a reader from the pool, replacing it when the handler has
		// completed.  then set the underlying reader r.Body and reset to nil
		// when the handler has completed.
		sz := readerPool.Get().(*snappyframed.Reader)
		defer readerPool.Put(sz)
		sz.Reset(body)
		defer sz.Reset(nil)
		body = ioutil.NopCloser(sz)
	}

	// decode the an APIRequest from the request entity.
	var req *APIRequest
	err := json.NewDecoder(body).Decode(&req)
	if err != nil {
		http.Error(resp, "invalid request", http.StatusBadRequest)
		return
	}

	// encode the response as a snappyframed stream.  the timing of statements
	// here is important and tricky.  A real application would probably want to
	// implement an http.ResponseWriter capable of doing HTTP content
	// negotiation and performing Reset automatically on creation and on Close.
	resp.Header().Set("Content-Type", snappyframed.MediaType)
	w := writerPool.Get().(*snappyframed.Writer)
	defer writerPool.Put(w)
	w.Reset(resp)
	defer w.Reset(nil)
	defer w.Close()

	json.NewEncoder(w).Encode(APIResponse{
		Messages: []string{
			fmt.Sprintf("hello %s", req.Name),
		},
	})
}

// This example shows how a sync.Pool might be used to speed up decoding and
// encoding of HTTP traffic.  Depending on your application such an approach
// may not provide any benefit.  Before making such a change it is important to
// instrument your system to measure performance gains.
func main() {
	server := httptest.NewServer(http.HandlerFunc(szAPIHandler))

	// encode a request body using the pool. in this case no defer statements
	// are used to clarify the order in which events happen.  some applications
	// may benefit from not using defer statements.
	req := APIRequest{"pooling example"}
	var reqbuf bytes.Buffer
	enc := writerPool.Get().(*snappyframed.Writer)
	enc.Reset(&reqbuf)
	json.NewEncoder(enc).Encode(req)
	enc.Close()
	enc.Reset(nil)
	writerPool.Put(enc)

	resp, err := http.Post(server.URL, snappyframed.MediaType, &reqbuf)
	if err != nil {
		panic(err)
	}

	// decode the response as a snappyframed stream.  don't bother unmarshaling
	// the response in this case and just write it to stdout.
	defer resp.Body.Close()
	if resp.Header.Get("Content-Type") == snappyframed.MediaType {
		sz := readerPool.Get().(*snappyframed.Reader)
		defer readerPool.Put(sz)
		sz.Reset(resp.Body)
		defer sz.Reset(nil)
		resp.Body = ioutil.NopCloser(sz)
	}
	_, err = io.Copy(os.Stdout, resp.Body)
	if err != nil {
		panic(err)
	}
}
Output:

{"Messages":["hello pooling example"]}

Index

Examples

Constants

View Source
const ContentEncoding = "x-snappy-framed"

ContentEncoding is the appropriate HTTP Content-Encoding header value for requests containing a snappy framed entity body.

View Source
const Ext = ".sz"

Ext is the file extension for files whose content is a snappy framed stream.

View Source
const MediaType = "application/x-snappy-framed"

MediaType is the MIME type used to represent snappy framed content.

Variables

This section is empty.

Functions

This section is empty.

Types

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader is an io.Reader that can reads data decompressed from a compressed snappy framed stream read with an underlying io.Reader.

func NewReader

func NewReader(r io.Reader) *Reader

NewReader returns an new Reader. Reads from the Reader retreive data decompressed from a snappy framed stream read from sz.

func (*Reader) Read

func (sz *Reader) Read(b []byte) (int, error)

Read fills b with any decoded data remaining in the Reader's internal buffers. When buffers are empty the Reader attempts to decode a data chunk from the underlying to fill b with.

Read returns an error if the first chunk encountered in the underlying reader is not a snappy-framed stream identifier.

func (*Reader) Reset

func (sz *Reader) Reset(r io.Reader)

Reset discards internal state and sets the underlying reader to r. Reset does not alter the reader's verification of checksums. After Reset returns the reader is equivalent to one returned by NewReader. Reusing readers with Reset can significantly reduce allocation overhead in applications making heavy use of snappy framed format streams.

func (*Reader) WriteTo

func (sz *Reader) WriteTo(w io.Writer) (int64, error)

WriteTo implements the io.WriterTo interface used by io.Copy. It writes decoded data from the underlying reader to w. WriteTo returns the number of bytes written along with any error encountered.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer is an io.WriteCloser, Data written to a Writer is compressed and flushed to an underlying io.Writer.

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter returns a new Writer. Data written to the returned Writer is compressed and written to w. Before the first compressed chunked is written a snappy-framed stream identifier block is written to w.

The caller is responsible for calling Flush or Close after all writes have completed to guarantee all data has been encoded and written to w.

func (*Writer) Close

func (sz *Writer) Close() error

Close flushes the Writer and tears down internal data structures. Close does not close the underlying io.Writer.

func (*Writer) Flush

func (sz *Writer) Flush() error

Flush encodes any (decoded) source data buffered interanally in the Writer and writes a chunk containing the result to the underlying io.Writer.

func (*Writer) ReadFrom

func (sz *Writer) ReadFrom(r io.Reader) (int64, error)

ReadFrom implements the io.ReaderFrom interface used by io.Copy. It encodes data read from r as a snappy framed stream and writes the result to the underlying io.Writer. ReadFrom returns the number number of bytes read, along with any error encountered (other than io.EOF).

func (*Writer) Reset

func (sz *Writer) Reset(w io.Writer)

Reset discards internal state and sets the underlying writer to w. After Reset returns the writer is equivalent to one returned by NewWriter(w). Reusing writers with Reset can significantly reduce allocation overhead in applications making heavy use of snappy framed format streams.

func (*Writer) Write

func (sz *Writer) Write(p []byte) (int, error)

Write compresses the bytes of p and writes sequence of encoded chunks to the underlying io.Writer. Because decompressed data is buffered internally before encoding calls to Write may not always result in data being written to the underlying io.Writer.

Write returns 0 if and only if the returned error is non-nil.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL