grow resizes the data to a larger length. Requirement: to > from. If the file ended in a partial block, we fetch it, grow it, and write it back.
(e sqlExecutor, inodeID, from, to uint64)
| 121 | // If the file ended in a partial block, we fetch it, grow it, |
| 122 | // and write it back. |
| 123 | func grow(e sqlExecutor, inodeID, from, to uint64) error { |
| 124 | addRange := newBlockRange(from, to-from) |
| 125 | insertFrom := addRange.start |
| 126 | |
| 127 | if addRange.startOffset > 0 { |
| 128 | // We need to extend the original 'last block'. |
| 129 | // Fetch it, grow it, and update it. |
| 130 | // TODO(marc): this would be more efficient if we had RPAD for bytes. |
| 131 | data, err := getBlockData(e, inodeID, addRange.start) |
| 132 | if err != nil { |
| 133 | return err |
| 134 | } |
| 135 | data = append(data, make([]byte, addRange.startLength, addRange.startLength)...) |
| 136 | if err := updateBlockData(e, inodeID, addRange.start, data); err != nil { |
| 137 | return err |
| 138 | } |
| 139 | // We don't need to insert this block. |
| 140 | insertFrom++ |
| 141 | } |
| 142 | |
| 143 | insertTo := addRange.last |
| 144 | if insertTo < insertFrom { |
| 145 | return nil |
| 146 | } |
| 147 | |
| 148 | // Build the sql statement and blocks to insert. |
| 149 | // We don't share this functionality with 'write' because we can repeat empty blocks. |
| 150 | // This would be shorter if we weren't trying to be efficient. |
| 151 | // TODO(marc): this would also be better if we supported sparse files. |
| 152 | paramStrings := []string{} |
| 153 | params := []interface{}{} |
| 154 | count := 1 // placeholder count starts at 1. |
| 155 | if insertFrom != insertTo { |
| 156 | // We have full blocks. Only send a full block once. |
| 157 | for i := insertFrom; i < insertTo; i++ { |
| 158 | params = append(params, make([]byte, BlockSize, BlockSize)) |
| 159 | } |
| 160 | count++ |
| 161 | } |
| 162 | |
| 163 | // Go over all blocks that are certainly full. |
| 164 | for i := insertFrom; i < insertTo; i++ { |
| 165 | paramStrings = append(paramStrings, fmt.Sprintf("(%d, %d, ?)", inodeID, i)) |
| 166 | } |
| 167 | |
| 168 | // Check the last block. |
| 169 | if addRange.lastLength > 0 { |
| 170 | // Not empty, write it. It can't be a full block, because we |
| 171 | // would have an empty block right after. |
| 172 | params = append(params, make([]byte, addRange.lastLength, addRange.lastLength)) |
| 173 | paramStrings = append(paramStrings, fmt.Sprintf("(%d, %d, ?)", |
| 174 | inodeID, addRange.last)) |
| 175 | count++ |
| 176 | } |
| 177 | |
| 178 | if len(paramStrings) == 0 { |
| 179 | // We had only one block, and it was empty. Nothing do to. |
| 180 | return nil |