go-hep.org/x/hep@v0.38.1/xrootd/file.go (about)

     1  // Copyright ©2018 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package xrootd // import "go-hep.org/x/hep/xrootd"
     6  
     7  import (
     8  	"context"
     9  	rsync "sync"
    10  
    11  	"go-hep.org/x/hep/xrootd/xrdfs"
    12  	"go-hep.org/x/hep/xrootd/xrdproto/read"
    13  	"go-hep.org/x/hep/xrootd/xrdproto/stat"
    14  	"go-hep.org/x/hep/xrootd/xrdproto/sync"
    15  	"go-hep.org/x/hep/xrootd/xrdproto/truncate"
    16  	"go-hep.org/x/hep/xrootd/xrdproto/verifyw"
    17  	"go-hep.org/x/hep/xrootd/xrdproto/write"
    18  	"go-hep.org/x/hep/xrootd/xrdproto/xrdclose"
    19  )
    20  
    21  // File implements access to a content and meta information of file over XRootD.
    22  type file struct {
    23  	fs          *fileSystem
    24  	handle      xrdfs.FileHandle
    25  	compression *xrdfs.FileCompression
    26  
    27  	mu        rsync.RWMutex
    28  	info      *xrdfs.EntryStat
    29  	sessionID string
    30  }
    31  
    32  // Compression returns the compression info.
    33  func (f *file) Compression() *xrdfs.FileCompression {
    34  	return f.compression
    35  }
    36  
    37  // Info returns the cached stat info.
    38  // Note that it may return nil if info was not yet fetched and info may be not up-to-date.
    39  func (f *file) Info() *xrdfs.EntryStat {
    40  	return f.info
    41  }
    42  
    43  // Handle returns the file handle.
    44  func (f *file) Handle() xrdfs.FileHandle {
    45  	return f.handle
    46  }
    47  
    48  // Close closes the file.
    49  func (f *file) Close(ctx context.Context) error {
    50  	return f.do(ctx, func(ctx context.Context, sid string) (string, error) {
    51  		return f.fs.c.sendSession(ctx, sid, nil, &xrdclose.Request{Handle: f.handle})
    52  	})
    53  }
    54  
    55  // CloseVerify closes the file and checks whether the file has the provided size.
    56  // A zero size suppresses the verification.
    57  func (f *file) CloseVerify(ctx context.Context, size int64) error {
    58  	return f.do(ctx, func(ctx context.Context, sid string) (string, error) {
    59  		return f.fs.c.sendSession(ctx, sid, nil, &xrdclose.Request{Handle: f.handle, Size: size})
    60  	})
    61  }
    62  
    63  // Sync commits all pending writes to an open file.
    64  func (f *file) Sync(ctx context.Context) error {
    65  	return f.do(ctx, func(ctx context.Context, sid string) (string, error) {
    66  		return f.fs.c.sendSession(ctx, sid, nil, &sync.Request{Handle: f.handle})
    67  	})
    68  }
    69  
    70  // ReadAtContext reads len(p) bytes into p starting at offset off.
    71  func (f *file) ReadAtContext(ctx context.Context, p []byte, off int64) (n int, err error) {
    72  	resp := read.Response{Data: p}
    73  	req := &read.Request{Handle: f.handle, Offset: off, Length: int32(len(p))}
    74  	err = f.do(ctx, func(ctx context.Context, sid string) (string, error) {
    75  		return f.fs.c.sendSession(ctx, sid, &resp, req)
    76  	})
    77  	if err != nil {
    78  		return 0, err
    79  	}
    80  	return len(resp.Data), nil
    81  }
    82  
    83  // ReadAt reads len(p) bytes into p starting at offset off.
    84  func (f *file) ReadAt(p []byte, off int64) (n int, err error) {
    85  	return f.ReadAtContext(context.Background(), p, off)
    86  }
    87  
    88  // WriteAtContext writes len(p) bytes from p to the file at offset off.
    89  func (f *file) WriteAtContext(ctx context.Context, p []byte, off int64) error {
    90  	return f.do(ctx, func(ctx context.Context, sid string) (string, error) {
    91  		return f.fs.c.sendSession(ctx, sid, nil, &write.Request{Handle: f.handle, Offset: off, Data: p})
    92  	})
    93  }
    94  
    95  // WriteAt writes len(p) bytes from p to the file at offset off.
    96  func (f *file) WriteAt(p []byte, off int64) (n int, err error) {
    97  	err = f.WriteAtContext(context.Background(), p, off)
    98  	if err != nil {
    99  		return 0, err
   100  	}
   101  	return len(p), nil
   102  }
   103  
   104  // Truncate changes the size of the named file.
   105  func (f *file) Truncate(ctx context.Context, size int64) error {
   106  	return f.do(ctx, func(ctx context.Context, sid string) (string, error) {
   107  		return f.fs.c.sendSession(ctx, sid, nil, &truncate.Request{Handle: f.handle, Size: size})
   108  	})
   109  }
   110  
   111  // StatVirtualFS fetches the virtual fs stat info from the XRootD server.
   112  // TODO: note that calling stat with vfs and handle may be invalid.
   113  // See https://github.com/xrootd/xrootd/issues/728 for the details.
   114  func (f *file) StatVirtualFS(ctx context.Context) (xrdfs.VirtualFSStat, error) {
   115  	var resp stat.VirtualFSResponse
   116  	err := f.do(ctx, func(ctx context.Context, sid string) (string, error) {
   117  		return f.fs.c.sendSession(ctx, sid, &resp, &stat.Request{FileHandle: f.handle, Options: stat.OptionsVFS})
   118  	})
   119  	if err != nil {
   120  		return xrdfs.VirtualFSStat{}, err
   121  	}
   122  	return resp.VirtualFSStat, nil
   123  }
   124  
   125  // Stat fetches the stat info of this file from the XRootD server.
   126  // Note that Stat re-fetches value returned by the Info, so after the call to Stat
   127  // calls to Info may return different value than before.
   128  func (f *file) Stat(ctx context.Context) (xrdfs.EntryStat, error) {
   129  	f.mu.RLock()
   130  	sid := f.sessionID
   131  	f.mu.RUnlock()
   132  
   133  	var resp stat.DefaultResponse
   134  	sid, err := f.fs.c.sendSession(ctx, sid, &resp, &stat.Request{FileHandle: f.handle})
   135  	if err != nil {
   136  		return xrdfs.EntryStat{}, err
   137  	}
   138  
   139  	f.mu.Lock()
   140  	f.sessionID = sid
   141  	f.info = &resp.EntryStat
   142  	f.mu.Unlock()
   143  
   144  	return resp.EntryStat, nil
   145  }
   146  
   147  // VerifyWriteAt writes len(p) bytes from p to the file at offset off using crc32 verification.
   148  //
   149  // TODO: note that verifyw is not supported by the XRootD server.
   150  // See https://github.com/xrootd/xrootd/issues/738 for the details.
   151  func (f *file) VerifyWriteAt(ctx context.Context, p []byte, off int64) error {
   152  	return f.do(ctx, func(ctx context.Context, sid string) (string, error) {
   153  		return f.fs.c.sendSession(ctx, sid, nil, verifyw.NewRequestCRC32(f.handle, off, p))
   154  	})
   155  }
   156  
   157  func (f *file) do(ctx context.Context, fct func(ctx context.Context, sid string) (string, error)) error {
   158  	f.mu.RLock()
   159  	sid := f.sessionID
   160  	f.mu.RUnlock()
   161  
   162  	id, err := fct(ctx, sid)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	f.mu.Lock()
   168  	f.sessionID = id
   169  	f.mu.Unlock()
   170  
   171  	return nil
   172  }
   173  
   174  var (
   175  	_ xrdfs.File = (*file)(nil)
   176  )