Example #1
0
func (d *driver) deleteFromDir(diffInfo *pfs.DiffInfo, child *pfs.File, shard uint64) {
	childPath := child.Path
	dirPath := path.Dir(childPath)

	_append, ok := diffInfo.Appends[dirPath]
	if !ok {
		_append = newAppend(pfs.FileType_FILE_TYPE_DIR)
		diffInfo.Appends[dirPath] = _append
	}
	if _append.Children == nil {
		_append.Children = make(map[string]bool)
	}
	// Basically, we only set the entry to false if it's not been
	// set to true.  If it's been set to true, that means that there
	// is a PutFile operation in this commit for this very same file,
	// so we don't want to remove the file from the directory.
	if !_append.Children[childPath] {
		_append.Children[childPath] = false
		if diffInfo.ParentCommit != nil {
			_append.LastRef = d.lastRef(
				client.NewFile(diffInfo.ParentCommit.Repo.Name, diffInfo.ParentCommit.ID, dirPath),
				shard,
			)
		}
	}
}
Example #2
0
func (d *driver) addDirs(diffInfo *pfs.DiffInfo, child *pfs.File, shard uint64) {
	childPath := child.Path
	dirPath := path.Dir(childPath)
	for {
		_append, ok := diffInfo.Appends[dirPath]
		if !ok {
			_append = newAppend(pfs.FileType_FILE_TYPE_DIR)
			diffInfo.Appends[dirPath] = _append
		}
		if _append.Children == nil {
			_append.Children = make(map[string]bool)
		}
		_append.Children[childPath] = true
		if diffInfo.ParentCommit != nil {
			_append.LastRef = d.lastRef(
				client.NewFile(diffInfo.ParentCommit.Repo.Name, diffInfo.ParentCommit.ID, dirPath),
				shard,
			)
		}
		if dirPath == "." {
			break
		}
		childPath = dirPath
		dirPath = path.Dir(childPath)
	}
}
Example #3
0
func (d *driver) MakeDirectory(file *pfs.File, shard uint64) (retErr error) {
	defer func() {
		if retErr == nil {
			metrics.AddFiles(1)
		}
	}()
	d.lock.Lock()
	defer d.lock.Unlock()

	fileType, err := d.getFileType(file, shard)
	if err != nil {
		return err
	}

	if fileType == pfs.FileType_FILE_TYPE_REGULAR {
		return fmt.Errorf("%s already exists and is a file", file.Path)
	} else if fileType == pfs.FileType_FILE_TYPE_DIR {
		return nil
	}

	canonicalCommit, err := d.canonicalCommit(file.Commit)
	if err != nil {
		return err
	}
	diffInfo, ok := d.diffs.get(client.NewDiff(canonicalCommit.Repo.Name, canonicalCommit.ID, shard))
	if !ok {
		return pfsserver.NewErrCommitNotFound(canonicalCommit.Repo.Name, canonicalCommit.ID)
	}
	if diffInfo.Finished != nil {
		return fmt.Errorf("commit %s/%s has already been finished", canonicalCommit.Repo.Name, canonicalCommit.ID)
	}
	d.addDirs(diffInfo, file, shard)
	_append, ok := diffInfo.Appends[path.Clean(file.Path)]
	if !ok {
		_append = newAppend(pfs.FileType_FILE_TYPE_DIR)
	} else {
		_append.FileType = pfs.FileType_FILE_TYPE_DIR
	}
	if diffInfo.ParentCommit != nil {
		_append.LastRef = d.lastRef(
			client.NewFile(
				diffInfo.ParentCommit.Repo.Name,
				diffInfo.ParentCommit.ID,
				file.Path,
			),
			shard,
		)
	}
	diffInfo.Appends[path.Clean(file.Path)] = _append
	// The fact that this is a directory is signified by setting Children
	// to non-nil
	_append.Children = make(map[string]bool)
	return nil
}
Example #4
0
// If recurse is set to true, and if the file being inspected is a directory,
// its children will have the correct sizes.  If recurse is false and the file
// is a directory, its children will have size of 0.
// If unsafe is set to true, you can inspect files in an open commit
func (d *driver) inspectFile(file *pfs.File, filterShard *pfs.Shard, shard uint64,
	from *pfs.Commit, recurse bool, unsafe bool, handle string) (*pfs.FileInfo, []*pfs.BlockRef, error) {
	fileInfo := &pfs.FileInfo{File: file}
	var blockRefs []*pfs.BlockRef
	children := make(map[string]bool)
	deletedChildren := make(map[string]bool)
	commit, err := d.canonicalCommit(file.Commit)
	if err != nil {
		return nil, nil, err
	}
	for commit != nil && (from == nil || commit.ID != from.ID) {
		diffInfo, ok := d.diffs.get(client.NewDiff(commit.Repo.Name, commit.ID, shard))
		if !ok {
			return nil, nil, pfsserver.NewErrCommitNotFound(commit.Repo.Name, commit.ID)
		}
		if !unsafe && diffInfo.Finished == nil {
			commit = diffInfo.ParentCommit
			continue
		}
		if _append, ok := diffInfo.Appends[path.Clean(file.Path)]; ok {
			if _append.FileType == pfs.FileType_FILE_TYPE_NONE && !_append.Delete && len(_append.HandleDeletes) == 0 {
				return nil, nil, fmt.Errorf("the append for %s has file type NONE, this is likely a bug", path.Clean(file.Path))
			}
			if _append.FileType == pfs.FileType_FILE_TYPE_REGULAR {
				if fileInfo.FileType == pfs.FileType_FILE_TYPE_DIR {
					return nil, nil,
						fmt.Errorf("mixed dir and regular file %s/%s/%s, (this is likely a bug)", file.Commit.Repo.Name, file.Commit.ID, file.Path)
				}
				if fileInfo.FileType == pfs.FileType_FILE_TYPE_NONE {
					// the first time we find out it's a regular file we check
					// the file shard, dirs get returned regardless of sharding,
					// since they might have children from any shard
					if !pfsserver.FileInShard(filterShard, file) {
						return nil, nil, pfsserver.NewErrFileNotFound(file.Path, file.Commit.Repo.Name, file.Commit.ID)
					}
				}
				fileInfo.FileType = pfs.FileType_FILE_TYPE_REGULAR
				filtered := filterBlockRefs(filterShard, _append.BlockRefs)
				if handle == "" {
					for _, handleBlockRefs := range _append.Handles {
						filtered = append(filtered, filterBlockRefs(filterShard, handleBlockRefs.BlockRef)...)
					}
				} else {
					if handleBlockRefs, ok := _append.Handles[handle]; ok {
						filtered = append(filtered, filterBlockRefs(filterShard, handleBlockRefs.BlockRef)...)
					}
				}
				blockRefs = append(filtered, blockRefs...)
				for _, blockRef := range filtered {
					fileInfo.SizeBytes += (blockRef.Range.Upper - blockRef.Range.Lower)
				}
			} else if _append.FileType == pfs.FileType_FILE_TYPE_DIR {
				if fileInfo.FileType == pfs.FileType_FILE_TYPE_REGULAR {
					return nil, nil,
						fmt.Errorf("mixed dir and regular file %s/%s/%s, (this is likely a bug)", file.Commit.Repo.Name, file.Commit.ID, file.Path)
				}
				fileInfo.FileType = pfs.FileType_FILE_TYPE_DIR
				for child, add := range _append.Children {
					if !add {
						deletedChildren[child] = true
						continue
					}

					if !children[child] && !deletedChildren[child] {
						childFile := client.NewFile(commit.Repo.Name, commit.ID, child)
						if pfsserver.FileInShard(filterShard, childFile) {
							fileInfo.Children = append(
								fileInfo.Children,
								client.NewFile(commit.Repo.Name, commit.ID, child),
							)
							if recurse {
								childFileInfo, _, err := d.inspectFile(&pfs.File{
									Commit: file.Commit,
									Path:   child,
								}, filterShard, shard, from, recurse, unsafe, handle)
								if err != nil {
									return nil, nil, err
								}
								fileInfo.SizeBytes += childFileInfo.SizeBytes
							}
						}
					}
					children[child] = true
				}
			}
			// If Delete is true, then everything before this commit is irrelevant
			if _append.Delete || (unsafe && handle != "" && _append.HandleDeletes[handle]) {
				break
			}
			if fileInfo.CommitModified == nil {
				fileInfo.CommitModified = commit
				fileInfo.Modified = diffInfo.Finished
			}
			commit = _append.LastRef
			continue
		}
		commit = diffInfo.ParentCommit
	}
	if fileInfo.FileType == pfs.FileType_FILE_TYPE_NONE {
		return nil, nil, pfsserver.NewErrFileNotFound(file.Path, file.Commit.Repo.Name, file.Commit.ID)
	}
	return fileInfo, blockRefs, nil
}
Example #5
0
func (d *driver) PutFile(file *pfs.File, handle string,
	delimiter pfs.Delimiter, shard uint64, reader io.Reader) (retErr error) {
	blockClient, err := d.getBlockClient()
	if err != nil {
		return err
	}
	_client := client.APIClient{BlockAPIClient: blockClient}
	blockRefs, err := _client.PutBlock(delimiter, reader)
	if err != nil {
		return err
	}
	defer func() {
		if retErr == nil {
			metrics.AddFiles(1)
			for _, blockRef := range blockRefs.BlockRef {
				metrics.AddBytes(int64(blockRef.Range.Upper - blockRef.Range.Lower))
			}
		}
	}()
	d.lock.Lock()
	defer d.lock.Unlock()

	fileType, err := d.getFileType(file, shard)
	if err != nil {
		return err
	}

	if fileType == pfs.FileType_FILE_TYPE_DIR {
		return fmt.Errorf("%s is a directory", file.Path)
	}

	canonicalCommit, err := d.canonicalCommit(file.Commit)
	if err != nil {
		return err
	}
	diffInfo, ok := d.diffs.get(client.NewDiff(canonicalCommit.Repo.Name, canonicalCommit.ID, shard))
	if !ok {
		// This is a weird case since the commit existed above, it means someone
		// deleted the commit while the above code was running
		return pfsserver.NewErrCommitNotFound(canonicalCommit.Repo.Name, canonicalCommit.ID)
	}
	if diffInfo.Finished != nil {
		return fmt.Errorf("commit %s/%s has already been finished", canonicalCommit.Repo.Name, canonicalCommit.ID)
	}
	d.addDirs(diffInfo, file, shard)
	_append, ok := diffInfo.Appends[path.Clean(file.Path)]
	if !ok {
		_append = newAppend(pfs.FileType_FILE_TYPE_REGULAR)
	} else {
		_append.FileType = pfs.FileType_FILE_TYPE_REGULAR
	}
	if diffInfo.ParentCommit != nil {
		_append.LastRef = d.lastRef(
			client.NewFile(diffInfo.ParentCommit.Repo.Name, diffInfo.ParentCommit.ID, file.Path),
			shard,
		)
	}
	diffInfo.Appends[path.Clean(file.Path)] = _append
	if handle == "" {
		_append.BlockRefs = append(_append.BlockRefs, blockRefs.BlockRef...)
	} else {
		handleBlockRefs, ok := _append.Handles[handle]
		if !ok {
			handleBlockRefs = &pfs.BlockRefs{}
			_append.Handles[handle] = handleBlockRefs
		}
		handleBlockRefs.BlockRef = append(handleBlockRefs.BlockRef, blockRefs.BlockRef...)
	}
	for _, blockRef := range blockRefs.BlockRef {
		diffInfo.SizeBytes += blockRef.Range.Upper - blockRef.Range.Lower
	}
	return nil
}