2011-01-28 07:07:18 +00:00
/ *
2018-01-04 00:52:49 +00:00
Copyright 2011 The Perkeep Authors
2011-01-28 07:07:18 +00:00
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 .
* /
2013-07-08 01:52:14 +00:00
/ *
Package localdisk registers the "filesystem" blobserver storage type ,
storing blobs in a forest of sharded directories at the specified root .
Example low - level config :
"/storage/" : {
"handler" : "storage-filesystem" ,
"handlerArgs" : {
"path" : "/var/camlistore/blobs"
}
} ,
* /
Rename import paths from camlistore.org to perkeep.org.
Part of the project renaming, issue #981.
After this, users will need to mv their $GOPATH/src/camlistore.org to
$GOPATH/src/perkeep.org. Sorry.
This doesn't yet rename the tools like camlistored, camput, camget,
camtool, etc.
Also, this only moves the lru package to internal. More will move to
internal later.
Also, this doesn't yet remove the "/pkg/" directory. That'll likely
happen later.
This updates some docs, but not all.
devcam test now passes again, even with Go 1.10 (which requires vet
checks are clean too). So a bunch of vet tests are fixed in this CL
too, and a bunch of other broken tests are now fixed (introduced from
the past week of merging the CL backlog).
Change-Id: If580db1691b5b99f8ed6195070789b1f44877dd4
2018-01-01 22:41:41 +00:00
package localdisk // import "perkeep.org/pkg/blobserver/localdisk"
2010-07-11 04:18:16 +00:00
import (
2018-01-07 19:06:04 +00:00
"bytes"
2010-07-11 04:18:16 +00:00
"fmt"
2018-01-07 19:06:04 +00:00
"io/ioutil"
"log"
2010-12-14 02:20:31 +00:00
"os"
2014-02-07 18:45:43 +00:00
"path/filepath"
2011-04-03 15:07:40 +00:00
2018-01-03 05:03:30 +00:00
"perkeep.org/internal/osutil"
Rename import paths from camlistore.org to perkeep.org.
Part of the project renaming, issue #981.
After this, users will need to mv their $GOPATH/src/camlistore.org to
$GOPATH/src/perkeep.org. Sorry.
This doesn't yet rename the tools like camlistored, camput, camget,
camtool, etc.
Also, this only moves the lru package to internal. More will move to
internal later.
Also, this doesn't yet remove the "/pkg/" directory. That'll likely
happen later.
This updates some docs, but not all.
devcam test now passes again, even with Go 1.10 (which requires vet
checks are clean too). So a bunch of vet tests are fixed in this CL
too, and a bunch of other broken tests are now fixed (introduced from
the past week of merging the CL backlog).
Change-Id: If580db1691b5b99f8ed6195070789b1f44877dd4
2018-01-01 22:41:41 +00:00
"perkeep.org/pkg/blob"
"perkeep.org/pkg/blobserver"
2018-04-24 19:56:16 +00:00
"perkeep.org/pkg/blobserver/files"
Rename import paths from camlistore.org to perkeep.org.
Part of the project renaming, issue #981.
After this, users will need to mv their $GOPATH/src/camlistore.org to
$GOPATH/src/perkeep.org. Sorry.
This doesn't yet rename the tools like camlistored, camput, camget,
camtool, etc.
Also, this only moves the lru package to internal. More will move to
internal later.
Also, this doesn't yet remove the "/pkg/" directory. That'll likely
happen later.
This updates some docs, but not all.
devcam test now passes again, even with Go 1.10 (which requires vet
checks are clean too). So a bunch of vet tests are fixed in this CL
too, and a bunch of other broken tests are now fixed (introduced from
the past week of merging the CL backlog).
Change-Id: If580db1691b5b99f8ed6195070789b1f44877dd4
2018-01-01 22:41:41 +00:00
"perkeep.org/pkg/blobserver/local"
2016-06-15 17:06:37 +00:00
2015-12-01 16:19:49 +00:00
"go4.org/jsonconfig"
2016-06-15 17:06:37 +00:00
"go4.org/syncutil"
2010-07-11 04:18:16 +00:00
)
2018-04-30 23:23:43 +00:00
// TODO: rename DiskStorage to Storage.
2013-07-08 01:52:14 +00:00
// DiskStorage implements the blobserver.Storage interface using the
// local filesystem.
2011-05-09 16:11:18 +00:00
type DiskStorage struct {
2018-04-30 03:58:37 +00:00
blobserver . Storage
2018-04-30 23:23:43 +00:00
blob . SubFetcher
2018-04-24 19:56:16 +00:00
2018-04-30 03:58:37 +00:00
root string
2013-10-09 19:20:28 +00:00
// gen will be nil if partition != ""
gen * local . Generationer
2011-04-09 06:20:24 +00:00
}
2018-04-30 23:23:43 +00:00
// Validate we implement expected interfaces.
var (
_ blobserver . Storage = ( * DiskStorage ) ( nil )
_ blob . SubFetcher = ( * DiskStorage ) ( nil ) // for blobpacked; Issue 1136
)
2014-03-05 16:23:07 +00:00
func ( ds * DiskStorage ) String ( ) string {
return fmt . Sprintf ( "\"filesystem\" file-per-blob at %s" , ds . root )
}
2014-02-07 18:45:43 +00:00
// IsDir reports whether root is a localdisk (file-per-blob) storage directory.
func IsDir ( root string ) ( bool , error ) {
2018-04-24 19:56:16 +00:00
if osutil . DirExists ( filepath . Join ( root , "sha1" ) ) {
return true , nil
}
2014-02-07 18:45:43 +00:00
if osutil . DirExists ( filepath . Join ( root , blob . RefFromString ( "" ) . HashName ( ) ) ) {
return true , nil
}
return false , nil
}
2016-06-15 17:06:37 +00:00
const (
// We refuse to create a DiskStorage when the user's ulimit is lower than
// minFDLimit. 100 is ridiculously low, but the default value on OSX is 256, and we
// don't want to fail by default, so our min value has to be lower than 256.
minFDLimit = 100
recommendedFDLimit = 1024
)
2013-07-08 01:52:14 +00:00
// New returns a new local disk storage implementation at the provided
// root directory, which must already exist.
2012-11-07 19:55:37 +00:00
func New ( root string ) ( * DiskStorage , error ) {
2011-02-04 22:31:23 +00:00
// Local disk.
2012-11-07 19:55:37 +00:00
fi , err := os . Stat ( root )
if os . IsNotExist ( err ) {
2015-01-19 03:02:42 +00:00
// As a special case, we auto-created the "packed" directory for subpacked.
if filepath . Base ( root ) == "packed" {
if err := os . Mkdir ( root , 0700 ) ; err != nil {
return nil , fmt . Errorf ( "failed to mkdir packed directory: %v" , err )
}
fi , err = os . Stat ( root )
} else {
return nil , fmt . Errorf ( "Storage root %q doesn't exist" , root )
}
2011-02-04 22:31:23 +00:00
}
2012-11-07 19:55:37 +00:00
if err != nil {
2013-01-12 00:48:44 +00:00
return nil , fmt . Errorf ( "Failed to stat directory %q: %v" , root , err )
2012-11-07 19:55:37 +00:00
}
if ! fi . IsDir ( ) {
2017-12-10 09:13:00 +00:00
return nil , fmt . Errorf ( "storage root %q exists but is not a directory" , root )
2012-11-07 19:55:37 +00:00
}
2018-04-30 03:58:37 +00:00
fileSto := files . NewStorage ( files . OSFS ( ) , root )
2012-11-07 19:55:37 +00:00
ds := & DiskStorage {
2018-04-30 23:23:43 +00:00
Storage : fileSto ,
SubFetcher : fileSto ,
root : root ,
gen : local . NewGenerationer ( root ) ,
2013-11-29 00:33:01 +00:00
}
2012-11-07 19:55:37 +00:00
if _ , _ , err := ds . StorageGeneration ( ) ; err != nil {
return nil , fmt . Errorf ( "Error initialization generation for %q: %v" , root , err )
}
2016-06-15 17:06:37 +00:00
ul , err := osutil . MaxFD ( )
if err != nil {
if err == osutil . ErrNotSupported {
// Do not set the gate on Windows, since we don't know the ulimit.
return ds , nil
}
return nil , err
}
if ul < minFDLimit {
2017-12-10 09:13:00 +00:00
return nil , fmt . Errorf ( "the max number of open file descriptors on your system (ulimit -n) is too low. Please fix it with 'ulimit -S -n X' with X being at least %d" , recommendedFDLimit )
2016-06-15 17:06:37 +00:00
}
2018-01-30 11:02:56 +00:00
// Setting the gate to 80% of the ulimit, to leave a bit of room for other file ops happening in Perkeep.
// TODO(mpl): make this used and enforced Perkeep-wide. Issue #837.
2018-04-30 03:58:37 +00:00
fileSto . SetNewFileGate ( syncutil . NewGate ( int ( ul * 80 / 100 ) ) )
2018-01-07 19:06:04 +00:00
err = ds . checkFS ( )
if err != nil {
return nil , err
}
2012-11-07 19:55:37 +00:00
return ds , nil
2010-12-14 02:20:31 +00:00
}
Update from r60 to [almost] Go 1.
A lot is still broken, but most stuff at least compiles now.
The directory tree has been rearranged now too. Go libraries are now
under "pkg". Fully qualified, they are e.g. "camlistore.org/pkg/jsonsign".
The go tool cannot yet fetch from arbitrary domains, but discussion is
happening now on which mechanism to use to allow that.
For now, put the camlistore root under $GOPATH/src. Typically $GOPATH
is $HOME, so Camlistore should be at $HOME/src/camlistore.org.
Then you can:
$ go build ./server/camlistored
... etc
The build.pl script is currently disabled. It'll be resurrected at
some point, but with a very different role (helping create a fake
GOPATH and running the go build command, if things are installed at
the wrong place, and/or running fileembed generators).
Many things are certainly broken.
Many things are disabled. (MySQL, all indexing, etc).
Many things need to be moved into
camlistore.org/third_party/{code.google.com,github.com} and updated
from their r60 to Go 1 versions, where applicable.
The GoMySQL stuff should be updated to use database/sql and the ziutek
library implementing database/sql/driver.
Help wanted.
Change-Id: If71217dc5c8f0e70dbe46e9504ca5131c6eeacde
2012-02-19 05:53:06 +00:00
func newFromConfig ( _ blobserver . Loader , config jsonconfig . Obj ) ( storage blobserver . Storage , err error ) {
2013-01-12 00:48:44 +00:00
path := config . RequiredString ( "path" )
2011-04-03 15:07:40 +00:00
if err := config . Validate ( ) ; err != nil {
return nil , err
}
2013-01-12 00:48:44 +00:00
return New ( path )
2011-04-02 01:20:28 +00:00
}
func init ( ) {
blobserver . RegisterStorageConstructor ( "filesystem" , blobserver . StorageConstructor ( newFromConfig ) )
}
2018-01-07 19:06:04 +00:00
// checkFS verifies the DiskStorage root storage path
// operations include: stat, read/write file, mkdir, delete (files and directories)
2018-04-30 03:58:37 +00:00
//
// TODO: move this into the files package too?
2018-01-07 19:06:04 +00:00
func ( ds * DiskStorage ) checkFS ( ) ( ret error ) {
tempdir , err := ioutil . TempDir ( ds . root , "" )
if err != nil {
return fmt . Errorf ( "localdisk check: unable to create tempdir in %s, err=%v" , ds . root , err )
}
defer func ( ) {
err := os . RemoveAll ( tempdir )
if err != nil {
cleanErr := fmt . Errorf ( "localdisk check: unable to clean temp dir: %v" , err )
if ret == nil {
ret = cleanErr
} else {
log . Printf ( "WARNING: %v" , cleanErr )
}
}
} ( )
tempfile := filepath . Join ( tempdir , "FILE.tmp" )
filename := filepath . Join ( tempdir , "FILE" )
data := [ ] byte ( "perkeep rocks" )
err = ioutil . WriteFile ( tempfile , data , 0644 )
if err != nil {
return fmt . Errorf ( "localdisk check: unable to write into %s, err=%v" , ds . root , err )
}
out , err := ioutil . ReadFile ( tempfile )
if err != nil {
return fmt . Errorf ( "localdisk check: unable to read from %s, err=%v" , tempfile , err )
}
if bytes . Compare ( out , data ) != 0 {
return fmt . Errorf ( "localdisk check: tempfile contents didn't match, got=%q" , out )
}
if _ , err := os . Lstat ( filename ) ; ! os . IsNotExist ( err ) {
return fmt . Errorf ( "localdisk check: didn't expect file to exist, Lstat had other error, err=%v" , err )
}
if err := os . Rename ( tempfile , filename ) ; err != nil {
return fmt . Errorf ( "localdisk check: rename failed, err=%v" , err )
}
if _ , err := os . Lstat ( filename ) ; err != nil {
return fmt . Errorf ( "localdisk check: after rename passed Lstat had error, err=%v" , err )
}
return nil
}