1// Copyright 2014 Richard Lehane. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package siegreader 16 17import ( 18 "io" 19 "os" 20) 21 22// Buffers is a combined pool of stream, external and file buffers 23type Buffers struct { 24 spool *pool // Pool of stream Buffers 25 fpool *pool // Pool of file Buffers 26 epool *pool // Pool of external buffers 27 28 fdatas *datas // file datas 29} 30 31// New creates a new pool of stream, external and file buffers 32func New() *Buffers { 33 return &Buffers{ 34 spool: newPool(newStream), 35 fpool: newPool(newFile), 36 epool: newPool(newExternal), 37 fdatas: &datas{ 38 newPool(newBigFile), 39 newPool(newSmallFile), 40 newPool(newMmap), 41 }, 42 } 43} 44 45// Get returns a Buffer reading from the provided io.Reader. 46// Get returns a Buffer backed by a stream, external or file 47// source buffer depending on the type of reader. 48// Source buffers are re-cycled where possible. 49func (b *Buffers) Get(src io.Reader) (*Buffer, error) { 50 f, ok := src.(*os.File) 51 if ok { 52 stat, err := f.Stat() 53 if err != nil || stat.Mode()&os.ModeType != 0 { 54 ok = false 55 } 56 } 57 if !ok { 58 e, ok := src.(source) 59 if !ok || !e.IsSlicer() { 60 stream := b.spool.get().(*stream) 61 buf := &Buffer{} 62 err := stream.setSource(src, buf) 63 buf.bufferSrc = stream 64 return buf, err 65 } 66 ext := b.epool.get().(*external) 67 err := ext.setSource(e) 68 return &Buffer{bufferSrc: ext}, err 69 } 70 fbuf := b.fpool.get().(*file) 71 err := fbuf.setSource(f, b.fdatas) 72 return &Buffer{bufferSrc: fbuf}, err 73} 74 75// Put returns a Buffer to the pool for re-cycling. 76func (b *Buffers) Put(i *Buffer) { 77 switch v := i.bufferSrc.(type) { 78 default: 79 panic("Siegreader: unknown buffer type") 80 case *stream: 81 v.cleanUp() 82 b.spool.put(v) 83 case *file: 84 b.fdatas.put(v.data) 85 b.fpool.put(v) 86 case *external: 87 b.epool.put(v) 88 } 89} 90 91// data pool (used by file) 92// pool of big files, small files, and mmap files 93type datas struct { 94 bfpool *pool 95 sfpool *pool 96 mpool *pool 97} 98 99func (d *datas) get(f *file) data { 100 if mmapable(f.sz) { 101 m := d.mpool.get().(*mmap) 102 if err := m.setSource(f); err == nil { 103 return m 104 } 105 d.mpool.put(m) // replace on error and get big file instead 106 } 107 if f.sz <= int64(smallFileSz) { 108 sf := d.sfpool.get().(*smallfile) 109 sf.setSource(f) 110 return sf 111 } 112 bf := d.bfpool.get().(*bigfile) 113 bf.setSource(f) 114 return bf 115} 116 117func (d *datas) put(i data) { 118 if i == nil { 119 return 120 } 121 switch v := i.(type) { 122 default: 123 panic("Siegreader: unknown data type") 124 case *bigfile: 125 d.bfpool.put(v) 126 case *smallfile: 127 d.sfpool.put(v) 128 case *mmap: 129 v.reset() 130 d.mpool.put(v) 131 } 132 return 133} 134