@@ -232,7 +232,7 @@ func (t *Tracker) createOpen(w http.ResponseWriter, r *http.Request) {
232232 return
233233 }
234234 }
235- d , err := findAliveDevice (t .db , int64 (size ), nil )
235+ d , err := findAliveDevice (t .db , int64 (size ), nil , getClientIP ( r ) )
236236 if err == errNoDeviceAvailable {
237237 http .Error (w , "no device available" , http .StatusServiceUnavailable )
238238 return
@@ -262,6 +262,10 @@ func (t *Tracker) createOpen(w http.ResponseWriter, r *http.Request) {
262262var errNoDeviceAvailable = errors .New ("no device available" )
263263
264264type aliveDevice struct {
265+ zoneid int64
266+ rackid int64
267+ hostid int64
268+ hostip string
265269 hostname string
266270 httpPort int64
267271 devid int64
@@ -271,7 +275,7 @@ func (d *aliveDevice) PatchURL(fid int64) string {
271275 return fmt .Sprintf ("http://%s:%d/dev%d/%s" , d .hostname , d .httpPort , d .devid , vivify (fid ))
272276}
273277
274- func findAliveDevice (db * sql.DB , size int64 , devids []int64 ) (* aliveDevice , error ) {
278+ func findAliveDevice (db * sql.DB , size int64 , devids []int64 , clientIP string ) (* aliveDevice , error ) {
275279 var devidsSQL string
276280 if len (devids ) > 0 {
277281 var devidsString []string
@@ -282,9 +286,11 @@ func findAliveDevice(db *sql.DB, size int64, devids []int64) (*aliveDevice, erro
282286 } else {
283287 devidsSQL = "and d.status='alive' "
284288 }
285- rows , err := db .Query ("select h. hostname, d.write_port , d.devid " +
289+ rows , err := db .Query ("select z.zoneid, r.rackid, h.hostid, h.hostip, h. hostname, d.devid , d.write_port " +
286290 "from device d " +
287291 "join host h on d.hostid=h.hostid " +
292+ "join rack r on h.rackid=r.rackid " +
293+ "join zone z on r.zoneid=z.zoneid " +
288294 "where h.status='alive' " +
289295 "and bytes_free>= ? " +
290296 devidsSQL +
@@ -297,7 +303,7 @@ func findAliveDevice(db *sql.DB, size int64, devids []int64) (*aliveDevice, erro
297303 defer rows .Close () // nolint: errcheck
298304 for rows .Next () {
299305 var d aliveDevice
300- err = rows .Scan (& d .hostname , & d .httpPort , & d .devid )
306+ err = rows .Scan (& d .zoneid , & d .rackid , & d .hostid , & d . hostip , & d . hostname , & d . devid , & d . httpPort )
301307 if err != nil {
302308 return nil , err
303309 }
@@ -307,6 +313,27 @@ func findAliveDevice(db *sql.DB, size int64, devids []int64) (*aliveDevice, erro
307313 if err != nil {
308314 return nil , err
309315 }
316+ sameHostDevices := filterSameHost (devices , clientIP )
317+ if len (sameHostDevices ) > 0 {
318+ devices = sameHostDevices
319+ } else {
320+ subnets , err := getSubnets (db )
321+ if err != nil {
322+ return nil , err
323+ }
324+ rackID , zoneID , ok := getRackID (subnets , clientIP )
325+ if ok {
326+ sameRackDevices := filterSameRack (devices , rackID )
327+ if len (sameRackDevices ) > 0 {
328+ devices = sameRackDevices
329+ } else {
330+ sameZoneDevices := filterSameZone (devices , zoneID )
331+ if len (sameZoneDevices ) > 0 {
332+ devices = sameZoneDevices
333+ }
334+ }
335+ }
336+ }
310337 if len (devices ) == 0 {
311338 return nil , errNoDeviceAvailable
312339 }
@@ -317,6 +344,82 @@ func findAliveDevice(db *sql.DB, size int64, devids []int64) (*aliveDevice, erro
317344 return & devices [rand .Intn (len (devices ))], nil
318345}
319346
347+ func getRackID (subnets []subnet , clientIP string ) (rackid , zoneid int64 , ok bool ) {
348+ ip := net .ParseIP (clientIP )
349+ for _ , s := range subnets {
350+ _ , ipnet , err := net .ParseCIDR (s .subnet )
351+ if err != nil {
352+ continue
353+ }
354+ if ipnet .Contains (ip ) {
355+ return s .rackid , s .zoneid , true
356+ }
357+ }
358+ return 0 , 0 , false
359+ }
360+
361+ func filterSameRack (devices []aliveDevice , rackID int64 ) []aliveDevice {
362+ var ret []aliveDevice
363+ for _ , d := range devices {
364+ if d .rackid == rackID {
365+ ret = append (ret , d )
366+ }
367+ }
368+ return ret
369+ }
370+
371+ func filterSameZone (devices []aliveDevice , zoneID int64 ) []aliveDevice {
372+ var ret []aliveDevice
373+ for _ , d := range devices {
374+ if d .zoneid == zoneID {
375+ ret = append (ret , d )
376+ }
377+ }
378+ return ret
379+ }
380+
381+ func getClientIP (req * http.Request ) string {
382+ xff := req .Header .Get ("x-forwarded-for" )
383+ if xff != "" {
384+ return strings .TrimSpace (strings .Split (xff , "," )[0 ])
385+ }
386+ return req .RemoteAddr
387+ }
388+
389+ func filterSameHost (devices []aliveDevice , clientIP string ) []aliveDevice {
390+ var ret []aliveDevice
391+ for _ , d := range devices {
392+ if d .hostip == clientIP {
393+ ret = append (ret , d )
394+ }
395+ }
396+ return ret
397+ }
398+
399+ type subnet struct {
400+ subnetid int64
401+ rackid int64
402+ zoneid int64
403+ subnet string
404+ }
405+
406+ func getSubnets (db * sql.DB ) ([]subnet , error ) {
407+ var ret []subnet
408+ rows , err := db .Query ("select subnetid, r.rackid, z.zoneid, subnet from subnet s join rack r on s.rackid=r.rackid join zone z on z.zoneid=r.zoneid" )
409+ if err != nil {
410+ return nil , err
411+ }
412+ for rows .Next () {
413+ var s subnet
414+ err = rows .Scan (& s .subnetid , & s .rackid , & s .zoneid , & s .subnet )
415+ if err != nil {
416+ return nil , err
417+ }
418+ ret = append (ret , s )
419+ }
420+ return ret , rows .Err ()
421+ }
422+
320423func (t * Tracker ) createClose (w http.ResponseWriter , r * http.Request ) {
321424 if r .Method != http .MethodPost {
322425 http .Error (w , http .StatusText (http .StatusMethodNotAllowed ), http .StatusMethodNotAllowed )
0 commit comments