write commits data to the blocks starting at 'offset' Amount of data to write must be non-zero. If offset is greated than 'originalSize', the file is grown first. We always write all or nothing.
(e sqlExecutor, inodeID, originalSize, offset uint64, data []byte)
| 226 | // If offset is greated than 'originalSize', the file is grown first. |
| 227 | // We always write all or nothing. |
| 228 | func write(e sqlExecutor, inodeID, originalSize, offset uint64, data []byte) error { |
| 229 | if offset > originalSize { |
| 230 | diff := offset - originalSize |
| 231 | if diff > BlockSize*2 { |
| 232 | // we need to grow the file by at least two blocks. Use growing method |
| 233 | // which only sends empty blocks once. |
| 234 | if err := grow(e, inodeID, originalSize, offset); err != nil { |
| 235 | return err |
| 236 | } |
| 237 | originalSize = offset |
| 238 | } else if diff > 0 { |
| 239 | // don't grow the file first, just change what we need to write. |
| 240 | data = append(make([]byte, diff, diff), data...) |
| 241 | offset = originalSize |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | // Now we know that offset is <= originalSize. |
| 246 | writeRange := newBlockRange(offset, uint64(len(data))) |
| 247 | writeFrom := writeRange.start |
| 248 | |
| 249 | if writeRange.startOffset > 0 { |
| 250 | // We're partially overwriting a block (this includes appending |
| 251 | // to the last block): fetch it, grow it, and update it. |
| 252 | // TODO(marc): this would be more efficient if we had RPAD for bytes. |
| 253 | blockData, err := getBlockData(e, inodeID, writeRange.start) |
| 254 | if err != nil { |
| 255 | return err |
| 256 | } |
| 257 | blockData = append(blockData[:writeRange.startOffset], data[:writeRange.startLength]...) |
| 258 | data = data[writeRange.startLength:] |
| 259 | if err := updateBlockData(e, inodeID, writeRange.start, blockData); err != nil { |
| 260 | return err |
| 261 | } |
| 262 | // We don't need to insert this block. |
| 263 | writeFrom++ |
| 264 | } |
| 265 | |
| 266 | writeTo := writeRange.last |
| 267 | if writeRange.lastLength == 0 { |
| 268 | // Last block is empty, don't update/insert it. |
| 269 | writeTo-- |
| 270 | } |
| 271 | if writeTo < writeFrom { |
| 272 | return nil |
| 273 | } |
| 274 | |
| 275 | // Figure out last existing block. Needed to tell the difference |
| 276 | // between insert and update. |
| 277 | lastBlock := int(originalSize / BlockSize) |
| 278 | if originalSize%BlockSize == 0 { |
| 279 | // Empty blocks do not exist (size=0 -> lastblock=-1). |
| 280 | lastBlock-- |
| 281 | } |
| 282 | |
| 283 | // Process updates first. |
| 284 | for i := writeFrom; i <= writeTo; i++ { |
| 285 | if i > lastBlock { |