瀏覽代碼

Move IOS fs.readStream buffer to heap

Ben Hsieh 8 年之前
父節點
當前提交
22db84f470
共有 2 個文件被更改,包括 141 次插入134 次删除
  1. 8
    4
      src/ios/RNFetchBlobFS.m
  2. 133
    130
      test/test-0.9.4.js

+ 8
- 4
src/ios/RNFetchBlobFS.m 查看文件

@@ -127,12 +127,12 @@ NSMutableDictionary *fileStreams = nil;
127 127
     [[self class] getPathFromUri:uri completionHandler:^(NSString *path, ALAssetRepresentation *asset) {
128 128
     
129 129
         RCTEventDispatcher * event = bridgeRef.eventDispatcher;
130
+        int read = 0;
131
+        int chunkSize = bufferSize;
132
+        // allocate buffer in heap instead of stack
133
+        uint8_t * buffer = (uint8_t *) malloc(bufferSize);
130 134
         @try
131 135
         {
132
-            int read = 0;
133
-            int chunkSize = bufferSize;
134
-            uint8_t * buffer[bufferSize];
135
-            
136 136
             if(path != nil)
137 137
             {
138 138
                 if([[NSFileManager defaultManager] fileExistsAtPath:path] == NO)
@@ -140,6 +140,7 @@ NSMutableDictionary *fileStreams = nil;
140 140
                     NSString * message = [NSString stringWithFormat:@"File not exists at path %@", path];
141 141
                     NSDictionary * payload = @{ @"event": FS_EVENT_ERROR, @"detail": message };
142 142
                     [event sendDeviceEventWithName:streamId body:payload];
143
+                    free(buffer);
143 144
                     return ;
144 145
                 }
145 146
                 NSInputStream * stream = [[NSInputStream alloc] initWithFileAtPath:path];
@@ -165,6 +166,7 @@ NSMutableDictionary *fileStreams = nil;
165 166
                 NSDictionary * payload = @{ @"event": FS_EVENT_ERROR, @"detail": @"RNFetchBlob.readStream unable to resolve URI" };
166 167
                 [event sendDeviceEventWithName:streamId body:payload];
167 168
             }
169
+            
168 170
         }
169 171
         @catch (NSError * err)
170 172
         {
@@ -173,6 +175,8 @@ NSMutableDictionary *fileStreams = nil;
173 175
         }
174 176
         @finally
175 177
         {
178
+            // release buffer
179
+            free(buffer);
176 180
             NSDictionary * payload = @{ @"event": FS_EVENT_END, @"detail": @"" };
177 181
             [event sendDeviceEventWithName:streamId body:payload];
178 182
         }

+ 133
- 130
test/test-0.9.4.js 查看文件

@@ -27,84 +27,84 @@ const dirs = RNFetchBlob.fs.dirs
27 27
 
28 28
 let prefix = ((Platform.OS === 'android') ? 'file://' : '')
29 29
 
30
-describe('issue #105', (report, done) => {
31
-  let tmp = null
32
-  RNFetchBlob
33
-    .config({ fileCache : true })
34
-    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
35
-    .then((res) => {
36
-      tmp = res.path()
37
-      return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {
38
-        'Content-Type' : 'multipart/form-data',
39
-        'Expect' : '100-continue'
40
-      }, [
41
-        { name : 'data', data : 'issue#105 test' },
42
-        { name : 'file', filename : 'github.png', data : RNFetchBlob.wrap(tmp) }
43
-      ])
44
-    })
45
-    .then((res) => {
46
-      done()
47
-    })
48
-})
49
-
50
-describe('issue #106', (report, done) => {
51
-
52
-  fetch('https://rnfb-test-app.firebaseapp.com/6m-json.json')
53
-    .then((res) => {
54
-      console.log('## converted')
55
-      return res.json()
56
-    })
57
-    .then((data) => {
58
-      // console.log(data)
59
-      report(<Assert key="fetch request success" expect={20000} actual={data.total}/>)
60
-      done()
61
-    })
62
-
63
-})
64
-
65
-describe('issue #111 get redirect destination', (report, done) => {
66
-  RNFetchBlob.fetch('GET', `${TEST_SERVER_URL}/redirect`)
67
-  .then((res) => {
68
-    report(
69
-      <Assert key="redirect history should tracable"
70
-        expect={2}
71
-        actual={res.info().redirects.length}/>,
72
-      <Assert key="redirect history verify"
73
-        expect={[`${TEST_SERVER_URL}/redirect`, `${TEST_SERVER_URL}/public/github.png`]}
74
-        comparer={Comparer.equalToArray}
75
-        actual={res.info().redirects}/>,
76
-    )
77
-    done()
78
-  })
79
-})
80
-
81
-describe('chunked encoding option test', (report, done) => {
82
-
83
-  let path = null
84
-  let base64 = null
85
-
86
-  RNFetchBlob
87
-    // .config({ fileCache : true })
88
-    .fetch('GET', `${TEST_SERVER_URL}/public/1600k-img-dummy.jpg`)
89
-    .then((res) => {
90
-      base64 = res.base64()
91
-      return RNFetchBlob
92
-        .fetch('POST', `${TEST_SERVER_URL}/upload`, {
93
-          'Content-Type' : 'application/octet-stream;BASE64'
94
-        }, base64)
95
-    })
96
-    .then((res) => {
97
-      let headers = res.info().headers
98
-      console.log(res.text())
99
-      report(<Assert key="request should not use chunked encoding"
100
-        expect={undefined}
101
-        actual={headers['transfer-encoding']}/>)
102
-      fs.unlink(path)
103
-      done()
104
-    })
105
-})
106
-
107
-describe('#118 ', (report, done) => {
30
+// describe('issue #105', (report, done) => {
31
+//   let tmp = null
32
+//   RNFetchBlob
33
+//     .config({ fileCache : true })
34
+//     .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
35
+//     .then((res) => {
36
+//       tmp = res.path()
37
+//       return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {
38
+//         'Content-Type' : 'multipart/form-data',
39
+//         'Expect' : '100-continue'
40
+//       }, [
41
+//         { name : 'data', data : 'issue#105 test' },
42
+//         { name : 'file', filename : 'github.png', data : RNFetchBlob.wrap(tmp) }
43
+//       ])
44
+//     })
45
+//     .then((res) => {
46
+//       done()
47
+//     })
48
+// })
49
+//
50
+// describe('issue #106', (report, done) => {
51
+//
52
+//   fetch('https://rnfb-test-app.firebaseapp.com/6m-json.json')
53
+//     .then((res) => {
54
+//       console.log('## converted')
55
+//       return res.json()
56
+//     })
57
+//     .then((data) => {
58
+//       // console.log(data)
59
+//       report(<Assert key="fetch request success" expect={20000} actual={data.total}/>)
60
+//       done()
61
+//     })
62
+//
63
+// })
64
+//
65
+// describe('issue #111 get redirect destination', (report, done) => {
66
+//   RNFetchBlob.fetch('GET', `${TEST_SERVER_URL}/redirect`)
67
+//   .then((res) => {
68
+//     report(
69
+//       <Assert key="redirect history should tracable"
70
+//         expect={2}
71
+//         actual={res.info().redirects.length}/>,
72
+//       <Assert key="redirect history verify"
73
+//         expect={[`${TEST_SERVER_URL}/redirect`, `${TEST_SERVER_URL}/public/github.png`]}
74
+//         comparer={Comparer.equalToArray}
75
+//         actual={res.info().redirects}/>,
76
+//     )
77
+//     done()
78
+//   })
79
+// })
80
+//
81
+// describe('chunked encoding option test', (report, done) => {
82
+//
83
+//   let path = null
84
+//   let base64 = null
85
+//
86
+//   RNFetchBlob
87
+//     // .config({ fileCache : true })
88
+//     .fetch('GET', `${TEST_SERVER_URL}/public/1600k-img-dummy.jpg`)
89
+//     .then((res) => {
90
+//       base64 = res.base64()
91
+//       return RNFetchBlob
92
+//         .fetch('POST', `${TEST_SERVER_URL}/upload`, {
93
+//           'Content-Type' : 'application/octet-stream;BASE64'
94
+//         }, base64)
95
+//     })
96
+//     .then((res) => {
97
+//       let headers = res.info().headers
98
+//       console.log(res.text())
99
+//       report(<Assert key="request should not use chunked encoding"
100
+//         expect={undefined}
101
+//         actual={headers['transfer-encoding']}/>)
102
+//       fs.unlink(path)
103
+//       done()
104
+//     })
105
+// })
106
+
107
+describe('#118 readStream performance prepare the file', (report, done) => {
108 108
   let cache = null
109 109
   let size = 0
110 110
   let tick = Date.now()
@@ -114,59 +114,62 @@ describe('#118 ', (report, done) => {
114 114
   RNFetchBlob.config({fileCache : true})
115 115
     .fetch('GET', `${TEST_SERVER_URL}/public/22mb-dummy`)
116 116
     .then((res) => {
117
+      report(<Info key="preparation complete"><Text>start in 3 seconds</Text></Info>)
117 118
       cache = res.path()
118
-      return fs.readStream(cache, 'utf8', 102400)
119
+      setTimeout(() => {
120
+        fs.readStream(cache, 'utf8', 102400)
121
+          .then((stream) => {
122
+            stream.open()
123
+            start = Date.now()
124
+            stream.onData((chunk) => {
125
+              count++
126
+              size += chunk.length
127
+              if(Date.now() - tick > 500) {
128
+                tick = Date.now()
129
+                report(
130
+                  <Info key="size" uid="100"><Text>{size} bytes read</Text></Info>)
131
+              }
132
+            })
133
+            stream.onEnd(() => {
134
+              report(
135
+                <Info key="size" uid="100"><Text>{size} bytes read</Text></Info>,
136
+                <Info key="elapsed"><Text>{Date.now() - start} ms</Text></Info>,
137
+                <Info key="events"><Text>{count} times</Text></Info>,
138
+                <Assert key="JS thread is not blocked" expect={true} actual={true}/>,)
139
+              fs.stat(cache).then((stat) => {
140
+                report(
141
+                  <Info key="info"><Text>{JSON.stringify(stat)}</Text></Info>)
142
+                fs.unlink(cache)
143
+                done()
144
+              })
145
+            })
146
+          })
147
+      }, 3000)
119 148
     })
120
-    .then((stream) => {
121
-      stream.open()
122
-      start = Date.now()
123
-      stream.onData((chunk) => {
124
-        count++
125
-        size += chunk.length
126
-        if(Date.now() - tick > 500) {
127
-          tick = Date.now()
128
-          report(
129
-            <Info key="size" uid="100"><Text>{size} bytes read</Text></Info>)
130
-        }
131
-      })
132
-      stream.onEnd(() => {
133
-        report(
134
-          <Info key="size" uid="100"><Text>{size} bytes read</Text></Info>,
135
-          <Info key="elapsed"><Text>{Date.now() - start} ms</Text></Info>,
136
-          <Info key="events"><Text>{count} times</Text></Info>,
137
-          <Assert key="JS thread is not blocked" expect={true} actual={true}/>,)
138
-        fs.stat(cache).then((stat) => {
139
-          report(
140
-            <Info key="info"><Text>{JSON.stringify(stat)}</Text></Info>)
141
-          fs.unlink(cache)
142
-        })
143
-      })
144
-    })
145
-
146 149
 })
147 150
 
148
-describe('issue #120 upload progress should work when sending body as-is', (report, done) => {
149
-
150
-  let data = RNTest.prop('image')
151
-  let tick = 0
152
-
153
-  let task = RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
154
-    Authorization : `Bearer ${DROPBOX_TOKEN}`,
155
-    'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+FILENAME+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
156
-    'Content-Type' : 'text/plain; charset=dropbox-cors-hack',
157
-  }, data)
158
-
159
-  task.uploadProgress((current, total) => {
160
-    tick ++
161
-  })
162
-  .then((res) => {
163
-    let resp = res.json()
164
-    report(
165
-      <Info key="viewer"><Text>{JSON.stringify(resp)}</Text></Info>,
166
-      <Assert key="event should be triggered"
167
-        expect={tick}
168
-        comparer={Comparer.greater} actual={0}/>)
169
-    done()
170
-  })
171
-
172
-})
151
+// describe('issue #120 upload progress should work when sending body as-is', (report, done) => {
152
+//
153
+//   let data = RNTest.prop('image')
154
+//   let tick = 0
155
+//
156
+//   let task = RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
157
+//     Authorization : `Bearer ${DROPBOX_TOKEN}`,
158
+//     'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+FILENAME+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
159
+//     'Content-Type' : 'text/plain; charset=dropbox-cors-hack',
160
+//   }, data)
161
+//
162
+//   task.uploadProgress((current, total) => {
163
+//     tick ++
164
+//   })
165
+//   .then((res) => {
166
+//     let resp = res.json()
167
+//     report(
168
+//       <Info key="viewer"><Text>{JSON.stringify(resp)}</Text></Info>,
169
+//       <Assert key="event should be triggered"
170
+//         expect={tick}
171
+//         comparer={Comparer.greater} actual={0}/>)
172
+//     done()
173
+//   })
174
+//
175
+// })