...

Source file src/github.com/Azure/azure-sdk-for-go/storage/pageblob.go

Documentation: github.com/Azure/azure-sdk-for-go/storage

     1  package storage
     2  
     3  // Copyright (c) Microsoft Corporation. All rights reserved.
     4  // Licensed under the MIT License. See License.txt in the project root for license information.
     5  
     6  import (
     7  	"encoding/xml"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"net/url"
    13  	"time"
    14  )
    15  
    16  // GetPageRangesResponse contains the response fields from
    17  // Get Page Ranges call.
    18  //
    19  // See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx
    20  type GetPageRangesResponse struct {
    21  	XMLName  xml.Name    `xml:"PageList"`
    22  	PageList []PageRange `xml:"PageRange"`
    23  }
    24  
    25  // PageRange contains information about a page of a page blob from
    26  // Get Pages Range call.
    27  //
    28  // See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx
    29  type PageRange struct {
    30  	Start int64 `xml:"Start"`
    31  	End   int64 `xml:"End"`
    32  }
    33  
    34  var (
    35  	errBlobCopyAborted    = errors.New("storage: blob copy is aborted")
    36  	errBlobCopyIDMismatch = errors.New("storage: blob copy id is a mismatch")
    37  )
    38  
    39  // PutPageOptions includes the options for a put page operation
    40  type PutPageOptions struct {
    41  	Timeout                           uint
    42  	LeaseID                           string     `header:"x-ms-lease-id"`
    43  	IfSequenceNumberLessThanOrEqualTo *int       `header:"x-ms-if-sequence-number-le"`
    44  	IfSequenceNumberLessThan          *int       `header:"x-ms-if-sequence-number-lt"`
    45  	IfSequenceNumberEqualTo           *int       `header:"x-ms-if-sequence-number-eq"`
    46  	IfModifiedSince                   *time.Time `header:"If-Modified-Since"`
    47  	IfUnmodifiedSince                 *time.Time `header:"If-Unmodified-Since"`
    48  	IfMatch                           string     `header:"If-Match"`
    49  	IfNoneMatch                       string     `header:"If-None-Match"`
    50  	RequestID                         string     `header:"x-ms-client-request-id"`
    51  }
    52  
    53  // WriteRange writes a range of pages to a page blob.
    54  // Ranges must be aligned with 512-byte boundaries and chunk must be of size
    55  // multiplies by 512.
    56  //
    57  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Page
    58  func (b *Blob) WriteRange(blobRange BlobRange, bytes io.Reader, options *PutPageOptions) error {
    59  	if bytes == nil {
    60  		return errors.New("bytes cannot be nil")
    61  	}
    62  	return b.modifyRange(blobRange, bytes, options)
    63  }
    64  
    65  // ClearRange clears the given range in a page blob.
    66  // Ranges must be aligned with 512-byte boundaries and chunk must be of size
    67  // multiplies by 512.
    68  //
    69  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Page
    70  func (b *Blob) ClearRange(blobRange BlobRange, options *PutPageOptions) error {
    71  	return b.modifyRange(blobRange, nil, options)
    72  }
    73  
    74  func (b *Blob) modifyRange(blobRange BlobRange, bytes io.Reader, options *PutPageOptions) error {
    75  	if blobRange.End < blobRange.Start {
    76  		return errors.New("the value for rangeEnd must be greater than or equal to rangeStart")
    77  	}
    78  	if blobRange.Start%512 != 0 {
    79  		return errors.New("the value for rangeStart must be a multiple of 512")
    80  	}
    81  	if blobRange.End%512 != 511 {
    82  		return errors.New("the value for rangeEnd must be a multiple of 512 - 1")
    83  	}
    84  
    85  	params := url.Values{"comp": {"page"}}
    86  
    87  	// default to clear
    88  	write := "clear"
    89  	var cl uint64
    90  
    91  	// if bytes is not nil then this is an update operation
    92  	if bytes != nil {
    93  		write = "update"
    94  		cl = (blobRange.End - blobRange.Start) + 1
    95  	}
    96  
    97  	headers := b.Container.bsc.client.getStandardHeaders()
    98  	headers["x-ms-blob-type"] = string(BlobTypePage)
    99  	headers["x-ms-page-write"] = write
   100  	headers["x-ms-range"] = blobRange.String()
   101  	headers["Content-Length"] = fmt.Sprintf("%v", cl)
   102  
   103  	if options != nil {
   104  		params = addTimeout(params, options.Timeout)
   105  		headers = mergeHeaders(headers, headersFromStruct(*options))
   106  	}
   107  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
   108  
   109  	resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, bytes, b.Container.bsc.auth)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	defer drainRespBody(resp)
   114  	return checkRespCode(resp, []int{http.StatusCreated})
   115  }
   116  
   117  // GetPageRangesOptions includes the options for a get page ranges operation
   118  type GetPageRangesOptions struct {
   119  	Timeout          uint
   120  	Snapshot         *time.Time
   121  	PreviousSnapshot *time.Time
   122  	Range            *BlobRange
   123  	LeaseID          string `header:"x-ms-lease-id"`
   124  	RequestID        string `header:"x-ms-client-request-id"`
   125  }
   126  
   127  // GetPageRanges returns the list of valid page ranges for a page blob.
   128  //
   129  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Get-Page-Ranges
   130  func (b *Blob) GetPageRanges(options *GetPageRangesOptions) (GetPageRangesResponse, error) {
   131  	params := url.Values{"comp": {"pagelist"}}
   132  	headers := b.Container.bsc.client.getStandardHeaders()
   133  
   134  	if options != nil {
   135  		params = addTimeout(params, options.Timeout)
   136  		params = addSnapshot(params, options.Snapshot)
   137  		if options.PreviousSnapshot != nil {
   138  			params.Add("prevsnapshot", timeRFC3339Formatted(*options.PreviousSnapshot))
   139  		}
   140  		if options.Range != nil {
   141  			headers["Range"] = options.Range.String()
   142  		}
   143  		headers = mergeHeaders(headers, headersFromStruct(*options))
   144  	}
   145  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
   146  
   147  	var out GetPageRangesResponse
   148  	resp, err := b.Container.bsc.client.exec(http.MethodGet, uri, headers, nil, b.Container.bsc.auth)
   149  	if err != nil {
   150  		return out, err
   151  	}
   152  	defer drainRespBody(resp)
   153  
   154  	if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
   155  		return out, err
   156  	}
   157  	err = xmlUnmarshal(resp.Body, &out)
   158  	return out, err
   159  }
   160  
   161  // PutPageBlob initializes an empty page blob with specified name and maximum
   162  // size in bytes (size must be aligned to a 512-byte boundary). A page blob must
   163  // be created using this method before writing pages.
   164  //
   165  // See CreateBlockBlobFromReader for more info on creating blobs.
   166  //
   167  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Blob
   168  func (b *Blob) PutPageBlob(options *PutBlobOptions) error {
   169  	if b.Properties.ContentLength%512 != 0 {
   170  		return errors.New("Content length must be aligned to a 512-byte boundary")
   171  	}
   172  
   173  	params := url.Values{}
   174  	headers := b.Container.bsc.client.getStandardHeaders()
   175  	headers["x-ms-blob-type"] = string(BlobTypePage)
   176  	headers["x-ms-blob-content-length"] = fmt.Sprintf("%v", b.Properties.ContentLength)
   177  	headers["x-ms-blob-sequence-number"] = fmt.Sprintf("%v", b.Properties.SequenceNumber)
   178  	headers = mergeHeaders(headers, headersFromStruct(b.Properties))
   179  	headers = b.Container.bsc.client.addMetadataToHeaders(headers, b.Metadata)
   180  
   181  	if options != nil {
   182  		params = addTimeout(params, options.Timeout)
   183  		headers = mergeHeaders(headers, headersFromStruct(*options))
   184  	}
   185  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
   186  
   187  	resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, nil, b.Container.bsc.auth)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	return b.respondCreation(resp, BlobTypePage)
   192  }
   193  

View as plain text