You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							189 lines
						
					
					
						
							4.4 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							189 lines
						
					
					
						
							4.4 KiB
						
					
					
				
								package wdclient
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"context"
							 | 
						|
									"fmt"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/pb"
							 | 
						|
									"google.golang.org/grpc"
							 | 
						|
									"strconv"
							 | 
						|
									"sync"
							 | 
						|
									"testing"
							 | 
						|
									"time"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								func TestLocationIndex(t *testing.T) {
							 | 
						|
									vm := &vidMap{}
							 | 
						|
									// test must be failed
							 | 
						|
									mustFailed := func(length int) {
							 | 
						|
										_, err := vm.getLocationIndex(length)
							 | 
						|
										if err == nil {
							 | 
						|
											t.Errorf("length %d must be failed", length)
							 | 
						|
										}
							 | 
						|
										if err.Error() != fmt.Sprintf("invalid length: %d", length) {
							 | 
						|
											t.Errorf("length %d must be failed. error: %v", length, err)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									mustFailed(-1)
							 | 
						|
									mustFailed(0)
							 | 
						|
								
							 | 
						|
									mustOk := func(length, cursor, expect int) {
							 | 
						|
										if length <= 0 {
							 | 
						|
											t.Fatal("please don't do this")
							 | 
						|
										}
							 | 
						|
										vm.cursor = int32(cursor)
							 | 
						|
										got, err := vm.getLocationIndex(length)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Errorf("length: %d, why? %v\n", length, err)
							 | 
						|
											return
							 | 
						|
										}
							 | 
						|
										if got != expect {
							 | 
						|
											t.Errorf("cursor: %d, length: %d, expect: %d, got: %d\n", cursor, length, expect, got)
							 | 
						|
											return
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									for i := -1; i < 100; i++ {
							 | 
						|
										mustOk(7, i, (i+1)%7)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// when cursor reaches MaxInt64
							 | 
						|
									mustOk(7, maxCursorIndex, 0)
							 | 
						|
								
							 | 
						|
									// test with constructor
							 | 
						|
									vm = newVidMap("")
							 | 
						|
									length := 7
							 | 
						|
									for i := 0; i < 100; i++ {
							 | 
						|
										got, err := vm.getLocationIndex(length)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Errorf("length: %d, why? %v\n", length, err)
							 | 
						|
											return
							 | 
						|
										}
							 | 
						|
										if got != i%length {
							 | 
						|
											t.Errorf("length: %d, i: %d, got: %d\n", length, i, got)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestLookupFileId(t *testing.T) {
							 | 
						|
									mc := NewMasterClient(grpc.EmptyDialOption{}, "", "", "", "", "", pb.ServerDiscovery{})
							 | 
						|
									length := 5
							 | 
						|
								
							 | 
						|
									//Construct a cache linked list of length 5
							 | 
						|
									for i := 0; i < length; i++ {
							 | 
						|
										mc.addLocation(uint32(i), Location{Url: strconv.FormatInt(int64(i), 10)})
							 | 
						|
										mc.resetVidMap()
							 | 
						|
									}
							 | 
						|
									for i := 0; i < length; i++ {
							 | 
						|
										locations, found := mc.GetLocations(uint32(i))
							 | 
						|
										if !found || len(locations) != 1 || locations[0].Url != strconv.FormatInt(int64(i), 10) {
							 | 
						|
											t.Fatalf("urls of vid=%d is not valid.", i)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									//When continue to add nodes to the linked list, the previous node will be deleted, and the cache of the response will be gone.
							 | 
						|
									for i := length; i < length+5; i++ {
							 | 
						|
										mc.addLocation(uint32(i), Location{Url: strconv.FormatInt(int64(i), 10)})
							 | 
						|
										mc.resetVidMap()
							 | 
						|
									}
							 | 
						|
									for i := 0; i < length; i++ {
							 | 
						|
										locations, found := mc.GetLocations(uint32(i))
							 | 
						|
										if found {
							 | 
						|
											t.Fatalf("urls of vid[%d] should not exists, but found: %v", i, locations)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									//The delete operation will be applied to all cache nodes
							 | 
						|
									_, found := mc.GetLocations(uint32(length))
							 | 
						|
									if !found {
							 | 
						|
										t.Fatalf("urls of vid[%d] not found", length)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									//If the locations of the current node exist, return directly
							 | 
						|
									newUrl := "abc"
							 | 
						|
									mc.addLocation(uint32(length), Location{Url: newUrl})
							 | 
						|
									locations, found := mc.GetLocations(uint32(length))
							 | 
						|
									if !found || locations[0].Url != newUrl {
							 | 
						|
										t.Fatalf("urls of vid[%d] not found", length)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									//After delete `abc`, cache nodes are searched
							 | 
						|
									deleteLoc := Location{Url: newUrl}
							 | 
						|
									mc.deleteLocation(uint32(length), deleteLoc)
							 | 
						|
									locations, found = mc.GetLocations(uint32(length))
							 | 
						|
									if found && locations[0].Url != strconv.FormatInt(int64(length), 10) {
							 | 
						|
										t.Fatalf("urls of vid[%d] not expected", length)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									//lock: concurrent test
							 | 
						|
									var wg sync.WaitGroup
							 | 
						|
									for i := 0; i < 20; i++ {
							 | 
						|
										wg.Add(1)
							 | 
						|
										go func() {
							 | 
						|
											defer wg.Done()
							 | 
						|
											for i := 0; i < 100; i++ {
							 | 
						|
												for i := 0; i < 20; i++ {
							 | 
						|
													_, _ = mc.GetLocations(uint32(i))
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}()
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									for i := 0; i < 100; i++ {
							 | 
						|
										mc.addLocation(uint32(i), Location{})
							 | 
						|
									}
							 | 
						|
									wg.Wait()
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestConcurrentGetLocations(t *testing.T) {
							 | 
						|
									mc := NewMasterClient(grpc.EmptyDialOption{}, "", "", "", "", "", pb.ServerDiscovery{})
							 | 
						|
									location := Location{Url: "TestDataRacing"}
							 | 
						|
									mc.addLocation(1, location)
							 | 
						|
								
							 | 
						|
									ctx, cancel := context.WithCancel(context.Background())
							 | 
						|
									wg := sync.WaitGroup{}
							 | 
						|
									for i := 0; i < 50; i++ {
							 | 
						|
										wg.Add(1)
							 | 
						|
										go func() {
							 | 
						|
											defer wg.Done()
							 | 
						|
											for {
							 | 
						|
												select {
							 | 
						|
												case <-ctx.Done():
							 | 
						|
													return
							 | 
						|
												default:
							 | 
						|
													_, found := mc.GetLocations(1)
							 | 
						|
													if !found {
							 | 
						|
														cancel()
							 | 
						|
														t.Error("vid map invalid due to data racing. ")
							 | 
						|
														return
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}()
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									//Simulate vidmap reset with cache when leader changes
							 | 
						|
									for i := 0; i < 100; i++ {
							 | 
						|
										mc.resetVidMap()
							 | 
						|
										mc.addLocation(1, location)
							 | 
						|
										time.Sleep(1 * time.Microsecond)
							 | 
						|
									}
							 | 
						|
									cancel()
							 | 
						|
									wg.Wait()
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func BenchmarkLocationIndex(b *testing.B) {
							 | 
						|
									b.SetParallelism(8)
							 | 
						|
									vm := vidMap{
							 | 
						|
										cursor: maxCursorIndex - 4000,
							 | 
						|
									}
							 | 
						|
									b.ResetTimer()
							 | 
						|
									b.RunParallel(func(pb *testing.PB) {
							 | 
						|
										for pb.Next() {
							 | 
						|
											_, err := vm.getLocationIndex(3)
							 | 
						|
											if err != nil {
							 | 
						|
												b.Error(err)
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								}
							 |