diff --git a/pkg/atomics/atomics.go b/pkg/atomics/atomics.go new file mode 100644 index 000000000..0b6795db2 --- /dev/null +++ b/pkg/atomics/atomics.go @@ -0,0 +1,37 @@ +/* +Copyright 2012 Google Inc. + +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 atomics + +import ( + "sync/atomic" +) + +type Bool struct { + v uint32 // 0 or 1, atomically +} + +func (b *Bool) Get() bool { + return atomic.LoadUint32(&b.v) != 0 +} + +func (b *Bool) Set(v bool) { + if v { + atomic.StoreUint32(&b.v, 1) + return + } + atomic.StoreUint32(&b.v, 0) +} diff --git a/pkg/schema/filereader.go b/pkg/schema/filereader.go index 2d06a06e6..01a942c04 100644 --- a/pkg/schema/filereader.go +++ b/pkg/schema/filereader.go @@ -25,6 +25,7 @@ import ( "os" "strings" + "camlistore.org/pkg/atomics" "camlistore.org/pkg/blobref" ) @@ -42,6 +43,8 @@ type FileReader struct { ss *Superset size int64 // total number of bytes + + readAll atomics.Bool // whether to preload aggressively } // NewFileReader returns a new FileReader reading the contents of fileBlobRef, @@ -75,6 +78,14 @@ func NewFileReader(fetcher blobref.SeekFetcher, fileBlobRef *blobref.BlobRef) (* return fr, nil } +// NewFileReader returns a new FileReader, reading bytes and blobs +// from the provided fetcher. +// +// NewFileReader does no fetch operation on the fetcher itself. The +// fetcher is only used in subsequent read operations. +// +// An error is only returned if the type of the Superset is not either +// "file" or "bytes". func (ss *Superset) NewFileReader(fetcher blobref.SeekFetcher) (*FileReader, error) { if ss.Type != "file" && ss.Type != "bytes" { return nil, fmt.Errorf("schema/filereader: Superset not of type \"file\" or \"bytes\"") @@ -139,6 +150,17 @@ func (fr *FileReader) ReadAt(p []byte, offset int64) (n int, err error) { return n, err } +func (fr *FileReader) WriteTo(w io.Writer) (n int64, err error) { + // WriteTo is called by io.Copy. Use this as a signal that we're going to want + // to read the rest of the file and go into an aggressive read-ahead mode. + fr.readAll.Set(true) + + // TODO: actually use readAll somehow. + + // Now just do a normal copy, but hide fr's WriteTo method from io.Copy: + return io.Copy(w, struct{ io.Reader }{fr}) +} + type sliceWriter struct { dst []byte }