multiple name supports
This commit is contained in:
Родитель
363c52589a
Коммит
2f387a1442
|
@ -43,6 +43,9 @@ func (this *FaultTolerantHdfsAccessor) OpenRead(path string) (ReadSeekCloser, er
|
||||||
}
|
}
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] OpenRead: %s", path, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] OpenRead: %s", path, err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +63,9 @@ func (this *FaultTolerantHdfsAccessor) ReadDir(path string) ([]Attrs, error) {
|
||||||
result, err := this.Impl.ReadDir(path)
|
result, err := this.Impl.ReadDir(path)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] ReadDir: %s", path, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] ReadDir: %s", path, err) {
|
||||||
return result, err
|
return result, err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +77,9 @@ func (this *FaultTolerantHdfsAccessor) Stat(path string) (Attrs, error) {
|
||||||
result, err := this.Impl.Stat(path)
|
result, err := this.Impl.Stat(path)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Stat: %s", path, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Stat: %s", path, err) {
|
||||||
return result, err
|
return result, err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +91,9 @@ func (this *FaultTolerantHdfsAccessor) StatFs() (FsInfo, error) {
|
||||||
result, err := this.Impl.StatFs()
|
result, err := this.Impl.StatFs()
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("StatFs: %s", err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("StatFs: %s", err) {
|
||||||
return result, err
|
return result, err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +105,9 @@ func (this *FaultTolerantHdfsAccessor) Mkdir(path string, mode os.FileMode) erro
|
||||||
err := this.Impl.Mkdir(path, mode)
|
err := this.Impl.Mkdir(path, mode)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Mkdir %s: %s", path, mode, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Mkdir %s: %s", path, mode, err) {
|
||||||
return err
|
return err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +119,9 @@ func (this *FaultTolerantHdfsAccessor) Remove(path string) error {
|
||||||
err := this.Impl.Remove(path)
|
err := this.Impl.Remove(path)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Remove: %s", path, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Remove: %s", path, err) {
|
||||||
return err
|
return err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,6 +133,9 @@ func (this *FaultTolerantHdfsAccessor) Rename(oldPath string, newPath string) er
|
||||||
err := this.Impl.Rename(oldPath, newPath)
|
err := this.Impl.Rename(oldPath, newPath)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Rename to %s: %s", oldPath, newPath, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("[%s] Rename to %s: %s", oldPath, newPath, err) {
|
||||||
return err
|
return err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +147,9 @@ func (this *FaultTolerantHdfsAccessor) Chmod(path string, mode os.FileMode) erro
|
||||||
err := this.Impl.Chmod(path, mode)
|
err := this.Impl.Chmod(path, mode)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("Chmod [%s] to [%d]: %s", path, mode, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("Chmod [%s] to [%d]: %s", path, mode, err) {
|
||||||
return err
|
return err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,6 +161,14 @@ func (this *FaultTolerantHdfsAccessor) Chown(path string, user, group string) er
|
||||||
err := this.Impl.Chown(path, user, group)
|
err := this.Impl.Chown(path, user, group)
|
||||||
if IsSuccessOrBenignError(err) || !op.ShouldRetry("Chown [%s] to [%s:%s]: %s", path, user, group, err) {
|
if IsSuccessOrBenignError(err) || !op.ShouldRetry("Chown [%s] to [%s:%s]: %s", path, user, group, err) {
|
||||||
return err
|
return err
|
||||||
|
}else{
|
||||||
|
// Clean up the bad connection, to let underline connection to get automatic refresh
|
||||||
|
this.Impl.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close underline connection if needed
|
||||||
|
func (this *FaultTolerantHdfsAccessor) Close() error {
|
||||||
|
return this.Impl.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ func TestStatWithRetries(t *testing.T) {
|
||||||
ftHdfsAccessor := NewFaultTolerantHdfsAccessor(hdfsAccessor, atMost2Attempts())
|
ftHdfsAccessor := NewFaultTolerantHdfsAccessor(hdfsAccessor, atMost2Attempts())
|
||||||
hdfsAccessor.EXPECT().Stat("/test/file").Return(Attrs{}, errors.New("Injected failure"))
|
hdfsAccessor.EXPECT().Stat("/test/file").Return(Attrs{}, errors.New("Injected failure"))
|
||||||
hdfsAccessor.EXPECT().Stat("/test/file").Return(Attrs{Name: "file"}, nil)
|
hdfsAccessor.EXPECT().Stat("/test/file").Return(Attrs{Name: "file"}, nil)
|
||||||
|
hdfsAccessor.EXPECT().Close().Return(nil)
|
||||||
attrs, err := ftHdfsAccessor.Stat("/test/file")
|
attrs, err := ftHdfsAccessor.Stat("/test/file")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "file", attrs.Name)
|
assert.Equal(t, "file", attrs.Name)
|
||||||
|
@ -41,6 +42,7 @@ func TestMkdirWithRetries(t *testing.T) {
|
||||||
ftHdfsAccessor := NewFaultTolerantHdfsAccessor(hdfsAccessor, atMost2Attempts())
|
ftHdfsAccessor := NewFaultTolerantHdfsAccessor(hdfsAccessor, atMost2Attempts())
|
||||||
hdfsAccessor.EXPECT().Mkdir("/test/dir", os.FileMode(0757)).Return(errors.New("Injected failure"))
|
hdfsAccessor.EXPECT().Mkdir("/test/dir", os.FileMode(0757)).Return(errors.New("Injected failure"))
|
||||||
hdfsAccessor.EXPECT().Mkdir("/test/dir", os.FileMode(0757)).Return(nil)
|
hdfsAccessor.EXPECT().Mkdir("/test/dir", os.FileMode(0757)).Return(nil)
|
||||||
|
hdfsAccessor.EXPECT().Close().Return(nil)
|
||||||
err := ftHdfsAccessor.Mkdir("/test/dir", os.FileMode(0757))
|
err := ftHdfsAccessor.Mkdir("/test/dir", os.FileMode(0757))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -54,6 +56,7 @@ func TestReadDirWithRetries(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
hdfsAccessor.EXPECT().ReadDir("/test/dir").Return(nil, errors.New("Injected failure"))
|
hdfsAccessor.EXPECT().ReadDir("/test/dir").Return(nil, errors.New("Injected failure"))
|
||||||
hdfsAccessor.EXPECT().ReadDir("/test/dir").Return(make([]Attrs, 10), nil)
|
hdfsAccessor.EXPECT().ReadDir("/test/dir").Return(make([]Attrs, 10), nil)
|
||||||
|
hdfsAccessor.EXPECT().Close().Return(nil)
|
||||||
result, err = ftHdfsAccessor.ReadDir("/test/dir")
|
result, err = ftHdfsAccessor.ReadDir("/test/dir")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 10, len(result))
|
assert.Equal(t, 10, len(result))
|
||||||
|
@ -69,6 +72,7 @@ func TestOpenReadWithRetries(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
hdfsAccessor.EXPECT().OpenRead("/test/file").Return(nil, errors.New("Injected failure"))
|
hdfsAccessor.EXPECT().OpenRead("/test/file").Return(nil, errors.New("Injected failure"))
|
||||||
hdfsAccessor.EXPECT().OpenRead("/test/file").Return(mockReader, nil)
|
hdfsAccessor.EXPECT().OpenRead("/test/file").Return(mockReader, nil)
|
||||||
|
hdfsAccessor.EXPECT().Close().Return(nil)
|
||||||
result, err = ftHdfsAccessor.OpenRead("/test/file")
|
result, err = ftHdfsAccessor.OpenRead("/test/file")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, mockReader, result.(*FaultTolerantHdfsReader).Impl)
|
assert.Equal(t, mockReader, result.(*FaultTolerantHdfsReader).Impl)
|
||||||
|
|
|
@ -35,8 +35,7 @@ func (this *FaultTolerantHdfsReader) Read(buffer []byte) (int, error) {
|
||||||
// Seeking to the right offset
|
// Seeking to the right offset
|
||||||
if err = this.Impl.Seek(this.Offset); err != nil {
|
if err = this.Impl.Seek(this.Offset); err != nil {
|
||||||
// Those errors are non-recoverable propagating right away
|
// Those errors are non-recoverable propagating right away
|
||||||
this.Impl.Close()
|
this.Close()
|
||||||
this.Impl = nil
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,9 +50,7 @@ func (this *FaultTolerantHdfsReader) Read(buffer []byte) (int, error) {
|
||||||
return nr, err
|
return nr, err
|
||||||
}
|
}
|
||||||
// On failure, we need to close the reader
|
// On failure, we need to close the reader
|
||||||
this.Impl.Close()
|
this.Close()
|
||||||
// and reset it to nil, so next time we attempt to re-open the file
|
|
||||||
this.Impl = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,5 +76,8 @@ func (this *FaultTolerantHdfsReader) Position() (int64, error) {
|
||||||
|
|
||||||
// Closes the stream
|
// Closes the stream
|
||||||
func (this *FaultTolerantHdfsReader) Close() error {
|
func (this *FaultTolerantHdfsReader) Close() error {
|
||||||
return this.Impl.Close()
|
err:= this.Impl.Close()
|
||||||
|
this.Impl = nil
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,12 @@ type HdfsAccessor interface {
|
||||||
EnsureConnected() error // Ensures HDFS accessor is connected to the HDFS name node
|
EnsureConnected() error // Ensures HDFS accessor is connected to the HDFS name node
|
||||||
Chown(path string, owner, group string) error // Changes the owner and group of the file
|
Chown(path string, owner, group string) error // Changes the owner and group of the file
|
||||||
Chmod(path string, mode os.FileMode) error // Changes the mode of the file
|
Chmod(path string, mode os.FileMode) error // Changes the mode of the file
|
||||||
|
Close() error // Close current meta connection if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
type hdfsAccessorImpl struct {
|
type hdfsAccessorImpl struct {
|
||||||
Clock Clock // interface to get wall clock time
|
Clock Clock // interface to get wall clock time
|
||||||
NameNodeAddresses []string // array of Address:port string for the name nodes
|
NameNodeAddresses []string // array of Address:port string for the name nodes
|
||||||
CurrentNameNodeIdx int // Index of the current name node in NameNodeAddresses array
|
|
||||||
MetadataClient *hdfs.Client // HDFS client used for metadata operations
|
MetadataClient *hdfs.Client // HDFS client used for metadata operations
|
||||||
MetadataClientMutex sync.Mutex // Serializing all metadata operations for simplicity (for now), TODO: allow N concurrent operations
|
MetadataClientMutex sync.Mutex // Serializing all metadata operations for simplicity (for now), TODO: allow N concurrent operations
|
||||||
UserNameToUidCache map[string]UidCacheEntry // cache for converting usernames to UIDs
|
UserNameToUidCache map[string]UidCacheEntry // cache for converting usernames to UIDs
|
||||||
|
@ -55,7 +55,6 @@ func NewHdfsAccessor(nameNodeAddresses string, clock Clock) (HdfsAccessor, error
|
||||||
|
|
||||||
this := &hdfsAccessorImpl{
|
this := &hdfsAccessorImpl{
|
||||||
NameNodeAddresses: nns,
|
NameNodeAddresses: nns,
|
||||||
CurrentNameNodeIdx: 0,
|
|
||||||
Clock: clock,
|
Clock: clock,
|
||||||
UserNameToUidCache: make(map[string]UidCacheEntry)}
|
UserNameToUidCache: make(map[string]UidCacheEntry)}
|
||||||
return this, nil
|
return this, nil
|
||||||
|
@ -82,21 +81,21 @@ func (this *hdfsAccessorImpl) ConnectMetadataClient() error {
|
||||||
// Establishes connection to a name node in the context of some other operation
|
// Establishes connection to a name node in the context of some other operation
|
||||||
func (this *hdfsAccessorImpl) ConnectToNameNode() (*hdfs.Client, error) {
|
func (this *hdfsAccessorImpl) ConnectToNameNode() (*hdfs.Client, error) {
|
||||||
// connecting to HDFS name node
|
// connecting to HDFS name node
|
||||||
nnAddr := this.NameNodeAddresses[this.CurrentNameNodeIdx]
|
client, err := this.connectToNameNodeImpl()
|
||||||
client, err := this.connectToNameNodeImpl(nnAddr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Connection failed, updating CurrentNameNodeIdx to try different name node next time
|
// Connection failed
|
||||||
this.CurrentNameNodeIdx = (this.CurrentNameNodeIdx + 1) % len(this.NameNodeAddresses)
|
return nil, errors.New(fmt.Sprintf("Fail to connect to name node with error: %s", err.Error()))
|
||||||
return nil, errors.New(fmt.Sprintf("%s: %s", nnAddr, err.Error()))
|
|
||||||
}
|
}
|
||||||
Info.Println("Connected to name node:", nnAddr)
|
Info.Println("Connected to name node")
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs an attempt to connect to the HDFS name
|
// Performs an attempt to connect to the HDFS name
|
||||||
func (this *hdfsAccessorImpl) connectToNameNodeImpl(nnAddr string) (*hdfs.Client, error) {
|
func (this *hdfsAccessorImpl) connectToNameNodeImpl() (*hdfs.Client, error) {
|
||||||
// Performing an attempt to connect to the name node
|
// Performing an attempt to connect to the name node
|
||||||
client, err := hdfs.New(nnAddr)
|
client, err := hdfs.NewClient(hdfs.ClientOptions{
|
||||||
|
Addresses: this.NameNodeAddresses,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -357,3 +356,16 @@ func (this *hdfsAccessorImpl) Chown(path string, user, group string) error {
|
||||||
}
|
}
|
||||||
return this.MetadataClient.Chown(path, user, group)
|
return this.MetadataClient.Chown(path, user, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close current connection if needed
|
||||||
|
func (this *hdfsAccessorImpl) Close() error {
|
||||||
|
this.MetadataClientMutex.Lock()
|
||||||
|
defer this.MetadataClientMutex.Unlock()
|
||||||
|
|
||||||
|
if(this.MetadataClient != nil) {
|
||||||
|
err:= this.MetadataClient.Close()
|
||||||
|
this.MetadataClient = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func NewNoRetryPolicy() *RetryPolicy {
|
||||||
func NewDefaultRetryPolicy(clock Clock) *RetryPolicy {
|
func NewDefaultRetryPolicy(clock Clock) *RetryPolicy {
|
||||||
return &RetryPolicy{
|
return &RetryPolicy{
|
||||||
Clock: clock,
|
Clock: clock,
|
||||||
MaxAttempts: 99999999999,
|
MaxAttempts: 10,
|
||||||
TimeLimit: 5 * time.Minute,
|
TimeLimit: 5 * time.Minute,
|
||||||
MinDelay: 1 * time.Second,
|
MinDelay: 1 * time.Second,
|
||||||
MaxDelay: 1 * time.Minute,
|
MaxDelay: 1 * time.Minute,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче