@ -5,7 +5,6 @@ import (
"code.google.com/p/weed-fs/go/storage"
"code.google.com/p/weed-fs/go/storage"
"code.google.com/p/weed-fs/go/topology"
"code.google.com/p/weed-fs/go/topology"
"errors"
"errors"
"fmt"
"math/rand"
"math/rand"
"sync"
"sync"
)
)
@ -19,188 +18,115 @@ This package is created to resolve these replica placement issues:
* /
* /
type VolumeGrowth struct {
type VolumeGrowth struct {
copy1factor int
copy2factor int
copy3factor int
copyAll int
accessLock sync . Mutex
accessLock sync . Mutex
}
}
func NewDefaultVolumeGrowth ( ) * VolumeGrowth {
func NewDefaultVolumeGrowth ( ) * VolumeGrowth {
return & VolumeGrowth { copy1factor : 7 , copy2factor : 6 , copy3factor : 3 }
return & VolumeGrowth { }
}
}
func ( vg * VolumeGrowth ) AutomaticGrowByType ( collection string , repType storage . ReplicationType , dataCenter string , topo * topology . Topology ) ( count int , err error ) {
// one replication type may need rp.GetCopyCount() actual volumes
factor := 1
// given copyCount, how many logical volumes to create
switch repType {
func ( vg * VolumeGrowth ) findVolumeCount ( copyCount int ) ( count int ) {
case storage . Copy000 :
switch copyCount {
factor = 1
case 1 :
count , err = vg . GrowByCountAndType ( vg . copy1factor , collection , repType , dataCenter , topo )
count = 7
case storage . Copy001 :
case 2 :
factor = 2
count = 6
count , err = vg . GrowByCountAndType ( vg . copy2factor , collection , repType , dataCenter , topo )
case 3 :
case storage . Copy010 :
count = 3
factor = 2
count , err = vg . GrowByCountAndType ( vg . copy2factor , collection , repType , dataCenter , topo )
case storage . Copy100 :
factor = 2
count , err = vg . GrowByCountAndType ( vg . copy2factor , collection , repType , dataCenter , topo )
case storage . Copy110 :
factor = 3
count , err = vg . GrowByCountAndType ( vg . copy3factor , collection , repType , dataCenter , topo )
case storage . Copy200 :
factor = 3
count , err = vg . GrowByCountAndType ( vg . copy3factor , collection , repType , dataCenter , topo )
default :
default :
err = errors . New ( "Unknown Replication Type!" )
count = 1
}
}
if count > 0 && count % factor == 0 {
return
}
func ( vg * VolumeGrowth ) AutomaticGrowByType ( collection string , rp * storage . ReplicaPlacement , preferredDataCenter string , topo * topology . Topology ) ( count int , err error ) {
count , err = vg . GrowByCountAndType ( vg . findVolumeCount ( rp . GetCopyCount ( ) ) , collection , rp , preferredDataCenter , topo )
if count > 0 && count % rp . GetCopyCount ( ) == 0 {
return count , nil
return count , nil
}
}
return count , err
return count , err
}
}
func ( vg * VolumeGrowth ) GrowByCountAndType ( count int , collection string , repType storage . ReplicationType , dataCenter string , topo * topology . Topology ) ( counter int , err error ) {
func ( vg * VolumeGrowth ) GrowByCountAndType ( targetC ount int , collection string , rp * storage . ReplicaPlacemen t , preferre dD ataCenter string , topo * topology . Topology ) ( counter int , err error ) {
vg . accessLock . Lock ( )
vg . accessLock . Lock ( )
defer vg . accessLock . Unlock ( )
defer vg . accessLock . Unlock ( )
counter = 0
for i := 0 ; i < targetCount ; i ++ {
switch repType {
if c , e := vg . findAndGrow ( topo , preferredDataCenter , collection , rp ) ; e == nil {
case storage . Copy000 :
counter += c
for i := 0 ; i < count ; i ++ {
} else {
if ok , server , vid := topo . RandomlyReserveOneVolume ( dataCenter ) ; ok {
return counter , e
if err = vg . grow ( topo , * vid , collection , repType , server ) ; err == nil {
counter ++
} else {
return counter , err
}
} else {
return counter , fmt . Errorf ( "Failed to grown volume for data center %s" , dataCenter )
}
}
case storage . Copy001 :
for i := 0 ; i < count ; i ++ {
//randomly pick one server from the datacenter, and then choose from the same rack
if ok , server1 , vid := topo . RandomlyReserveOneVolume ( dataCenter ) ; ok {
rack := server1 . Parent ( )
exclusion := make ( map [ string ] topology . Node )
exclusion [ server1 . String ( ) ] = server1
newNodeList := topology . NewNodeList ( rack . Children ( ) , exclusion )
if newNodeList . FreeSpace ( ) > 0 {
if ok2 , server2 := newNodeList . ReserveOneVolume ( rand . Intn ( newNodeList . FreeSpace ( ) ) , * vid ) ; ok2 {
if err = vg . grow ( topo , * vid , collection , repType , server1 , server2 ) ; err == nil {
counter ++
}
}
}
}
}
case storage . Copy010 :
for i := 0 ; i < count ; i ++ {
//randomly pick one server from the datacenter, and then choose from the a different rack
if ok , server1 , vid := topo . RandomlyReserveOneVolume ( dataCenter ) ; ok {
rack := server1 . Parent ( )
dc := rack . Parent ( )
exclusion := make ( map [ string ] topology . Node )
exclusion [ rack . String ( ) ] = rack
newNodeList := topology . NewNodeList ( dc . Children ( ) , exclusion )
if newNodeList . FreeSpace ( ) > 0 {
if ok2 , server2 := newNodeList . ReserveOneVolume ( rand . Intn ( newNodeList . FreeSpace ( ) ) , * vid ) ; ok2 {
if err = vg . grow ( topo , * vid , collection , repType , server1 , server2 ) ; err == nil {
counter ++
}
}
}
}
}
}
case storage . Copy100 :
}
for i := 0 ; i < count ; i ++ {
return
nl := topology . NewNodeList ( topo . Children ( ) , nil )
}
picked , ret := nl . RandomlyPickN ( 2 , 1 , dataCenter )
func ( vg * VolumeGrowth ) findAndGrow ( topo * topology . Topology , preferredDataCenter string , collection string , rp * storage . ReplicaPlacement ) ( int , error ) {
vid := topo . NextVolumeId ( )
servers , e := vg . findEmptySlotsForOneVolume ( topo , preferredDataCenter , rp )
if ret {
if e != nil {
var servers [ ] * topology . DataNode
return 0 , e
for _ , n := range picked {
}
if n . FreeSpace ( ) > 0 {
vid := topo . NextVolumeId ( )
if ok , server := n . ReserveOneVolume ( rand . Intn ( n . FreeSpace ( ) ) , vid , "" ) ; ok {
err := vg . grow ( topo , vid , collection , rp , servers ... )
servers = append ( servers , server )
return len ( servers ) , err
}
}
}
func ( vg * VolumeGrowth ) findEmptySlotsForOneVolume ( topo * topology . Topology , preferredDataCenter string , rp * storage . ReplicaPlacement ) ( servers [ ] * topology . DataNode , err error ) {
}
//find main datacenter and other data centers
if len ( servers ) == 2 {
mainDataCenter , otherDataCenters , dc_err := topo . RandomlyPickNodes ( rp . DiffDataCenterCount + 1 , func ( node topology . Node ) bool {
if err = vg . grow ( topo , vid , collection , repType , servers ... ) ; err == nil {
if preferredDataCenter != "" && node . IsDataCenter ( ) && node . Id ( ) != topology . NodeId ( preferredDataCenter ) {
counter ++
return false
}
}
} else {
return counter , fmt . Errorf ( "Failed to grown volume on data center %s and another data center" , dataCenter )
}
}
}
case storage . Copy110 :
return node . FreeSpace ( ) > rp . DiffRackCount + rp . SameRackCount + 1
for i := 0 ; i < count ; i ++ {
} )
nl := topology . NewNodeList ( topo . Children ( ) , nil )
if dc_err != nil {
picked , ret := nl . RandomlyPickN ( 2 , 2 , dataCenter )
return nil , dc_err
vid := topo . NextVolumeId ( )
}
if ret {
//find main rack and other racks
var servers [ ] * topology . DataNode
mainRack , otherRacks , rack_err := mainDataCenter . ( * topology . DataCenter ) . RandomlyPickNodes ( rp . DiffRackCount + 1 , func ( node topology . Node ) bool {
dc1 , dc2 := picked [ 0 ] , picked [ 1 ]
return node . FreeSpace ( ) > rp . SameRackCount + 1
if dc2 . FreeSpace ( ) > dc1 . FreeSpace ( ) {
} )
dc1 , dc2 = dc2 , dc1
if rack_err != nil {
}
return nil , rack_err
if dc1 . FreeSpace ( ) > 0 {
}
if ok , server1 := dc1 . ReserveOneVolume ( rand . Intn ( dc1 . FreeSpace ( ) ) , vid , "" ) ; ok {
//find main rack and other racks
servers = append ( servers , server1 )
mainServer , otherServers , server_err := mainRack . ( * topology . Rack ) . RandomlyPickNodes ( rp . SameRackCount + 1 , func ( node topology . Node ) bool {
rack := server1 . Parent ( )
return node . FreeSpace ( ) > 1
exclusion := make ( map [ string ] topology . Node )
} )
exclusion [ rack . String ( ) ] = rack
if server_err != nil {
newNodeList := topology . NewNodeList ( dc1 . Children ( ) , exclusion )
return nil , server_err
if newNodeList . FreeSpace ( ) > 0 {
}
if ok2 , server2 := newNodeList . ReserveOneVolume ( rand . Intn ( newNodeList . FreeSpace ( ) ) , vid ) ; ok2 {
servers = append ( servers , mainServer . ( * topology . DataNode ) )
servers = append ( servers , server2 )
for _ , server := range otherServers {
}
servers = append ( servers , server . ( * topology . DataNode ) )
}
}
}
for _ , rack := range otherRacks {
}
r := rand . Intn ( rack . FreeSpace ( ) )
if dc2 . FreeSpace ( ) > 0 {
if server , e := rack . ReserveOneVolume ( r ) ; e == nil {
if ok , server := dc2 . ReserveOneVolume ( rand . Intn ( dc2 . FreeSpace ( ) ) , vid , "" ) ; ok {
servers = append ( servers , server )
servers = append ( servers , server )
} else {
}
return servers , e
}
if len ( servers ) == 3 {
if err = vg . grow ( topo , vid , collection , repType , servers ... ) ; err == nil {
counter ++
}
}
}
}
}
case storage . Copy200 :
}
for i := 0 ; i < count ; i ++ {
for _ , datacenter := range otherDataCenters {
nl := topology . NewNodeList ( topo . Children ( ) , nil )
r := rand . Intn ( datacenter . FreeSpace ( ) )
picked , ret := nl . RandomlyPickN ( 3 , 1 , dataCenter )
if server , e := datacenter . ReserveOneVolume ( r ) ; e == nil {
vid := topo . NextVolumeId ( )
servers = append ( servers , server )
if ret {
} else {
var servers [ ] * topology . DataNode
return servers , e
for _ , n := range picked {
if n . FreeSpace ( ) > 0 {
if ok , server := n . ReserveOneVolume ( rand . Intn ( n . FreeSpace ( ) ) , vid , "" ) ; ok {
servers = append ( servers , server )
}
}
}
if len ( servers ) == 3 {
if err = vg . grow ( topo , vid , collection , repType , servers ... ) ; err == nil {
counter ++
}
}
}
}
}
}
}
return
return
}
}
func ( vg * VolumeGrowth ) grow ( topo * topology . Topology , vid storage . VolumeId , collection string , repType storage . ReplicationType , servers ... * topology . DataNode ) error {
func ( vg * VolumeGrowth ) grow ( topo * topology . Topology , vid storage . VolumeId , collection string , rp * storage . ReplicaPlacement , servers ... * topology . DataNode ) error {
for _ , server := range servers {
for _ , server := range servers {
if err := AllocateVolume ( server , vid , collection , re pType ) ; err == nil {
if err := AllocateVolume ( server , vid , collection , rp ) ; err == nil {
vi := storage . VolumeInfo { Id : vid , Size : 0 , Collection : collection , RepType : re pType , Version : storage . CurrentVersion }
vi := storage . VolumeInfo { Id : vid , Size : 0 , Collection : collection , ReplicaPlacement : rp , Version : storage . CurrentVersion }
server . AddOrUpdateVolume ( vi )
server . AddOrUpdateVolume ( vi )
topo . RegisterVolumeLayout ( & vi , server )
topo . RegisterVolumeLayout ( & vi , server )
glog . V ( 0 ) . Infoln ( "Created Volume" , vid , "on" , server )
glog . V ( 0 ) . Infoln ( "Created Volume" , vid , "on" , server )
xxxxxxxxxx