Project

General

Profile

5776-3.diff

Tomasz Domin, 06/09/2022 01:31 PM

Download (9.37 KB)

View differences:

new/src/com/goldencode/p2j/net/Protocol.java 2022-06-09 16:22:23 +0000
2 2
** Module   : Protocol.java
3 3
** Abstract : low level driver of the P2J protocol
4 4
**
5
** Copyright (c) 2005-2021, Golden Code Development Corporation.
5
** Copyright (c) 2005-2022, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- --JPRM-- ----------------Description-----------------
8 8
** 001 SIY 20050120   @19501 Created initial version.
......
76 76
** 026 IAS 20200930          Added JMX counters.
77 77
** 027 IAS 20201001          Ged rid of byte arrays allocations in objToByteArray().
78 78
**     IAS 20210325          Added SSLException catch
79
**     TJD 20220607          Writer/ByteArrayOutputStream memory leak fix for LOBs
79 80
*/
80 81
/*
81 82
** This program is free software: you can redistribute it and/or modify
......
464 465
               // form)
465 466
               Message msg = byteArrayToObj(data);
466 467
               
468
               // we can already release data memory here
469
               data = null;
470
               
467 471
               // hand the message to the dispatcher for processing
468 472
               queue.enqueueInbound(msg);
469 473
            }
......
597 601
   private class Writer
598 602
   implements Runnable
599 603
   {
600
      private final ByteArrayOutputStream2 baos = new ByteArrayOutputStream2(8192);
601
      private final ByteArrayOutputStream res = new ByteArrayOutputStream(8192);
604
      /**
605
       * Default size of buffer for object flattening
606
       */
607
      private static final int BUFFER_SIZE = 8192;
608

  
609
      /**
610
       * Pre-allocated helper buffers for object flattening
611
       */
612
      private ByteArrayOutputStream2 baos = new ByteArrayOutputStream2(BUFFER_SIZE);
613
      private ByteArrayOutputStream res = new ByteArrayOutputStream(BUFFER_SIZE);
614

  
615
      /**
616
       * Holder for data to be written out 
617
       */
602 618
      private byte[] data;
603 619
      
604 620
      /**
......
640 656
                  OUTGOING.update(data.length);
641 657
               }
642 658
               queue.write(data);
659

  
660
               // allow GC to collect memory allocated for data
661
               data = null;
643 662
            }
644 663
         }
645 664
         
......
723 742
         res.write(obj.getClass() == Message.class ? TYPE_MESSAGE : TYPE_SYNC_MESSAGE);
724 743
         res.write(baos.buf(), 0, baos.size());
725 744
         
726
         return res.toByteArray();
745
         // in case baos grows too big -> reallocate it
746
         if (baos.size() > BUFFER_SIZE)
747
         {
748
            baos = new ByteArrayOutputStream2(BUFFER_SIZE);
749
         }
750
         
751
         byte[] result = res.toByteArray();
752
         
753
         // in case res grows too big -> reallocate it
754
         if (res.size() > BUFFER_SIZE)
755
         {
756
            res = new ByteArrayOutputStream(BUFFER_SIZE);
757
         }
758
         
759
         return result;
727 760
      }
728 761
   }
729 762
}
new/src/com/goldencode/p2j/util/OutputStreamWrapper.java 2022-06-09 17:13:08 +0000
2 2
** Module   : OutputStreamWrapper.java
3 3
** Abstract : provides an external OutputStream wrapper for a P2J Stream
4 4
**
5
** Copyright (c) 2006-2017, Golden Code Development Corporation.
5
** Copyright (c) 2006-2022, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
8 8
** 001 GES 20060215   @24675 First version which provides an external
......
10 10
** 002 ECF 20171029          Made write(byte[], int, int) more efficient; implemented close to
11 11
**                           close underlying stream.
12 12
** 003 ME  20210322          Proxy flush to the underlying stream.
13
**     TJD 20220608          Chunked write implementation
13 14
*/
14 15
/*
15 16
** This program is free software: you can redistribute it and/or modify
......
80 81
   /** The wrapped stream. */
81 82
   private Stream out = null;
82 83
   
84
   /** 
85
    * The chunk to write at once to the remote {@link #stream}, via in the {@link #write(byte[], int, int)} 
86
    * implementation. 
87
    */
88
   private static final int WRITE_CHUNK_SIZE = 1024 * 1024; // 1MB
89
   
83 90
   /**
84 91
    * Creates an instance with the associated stream.
85 92
    */
......
103 110
   public void write(int b)
104 111
   throws IOException
105 112
   {
113
      if (out == null)
114
      {
115
         throw new IOException("Stream is not open.");
116
      }
106 117
      out.writeByte((byte) (b & 0xFF));
107 118
   }
108 119
   
......
124 135
   throws IOException,
125 136
          NullPointerException
126 137
   {
138
      if (out == null)
139
      {
140
         throw new IOException("Stream is not open.");
141
      }
127 142
      write(b, 0, b.length);
128 143
   }
129 144
   
......
154 169
          NullPointerException,
155 170
          IndexOutOfBoundsException
156 171
   {
157
      out.write(b, off, len);
172
      if (out == null)
173
      {
174
         throw new IOException("Stream is not open.");
175
      }
176
      // Bounds check
177
      if ((off + len) > b.length || off < 0 || len < 0)
178
      {
179
         throw new IndexOutOfBoundsException();
180
      }
181
      int remaining = len - off;
182
      if (remaining == 0)
183
      {
184
         return;
185
      }
186
      byte[] buffer = new byte[Math.min(remaining, WRITE_CHUNK_SIZE)];
187
      
188
      while (remaining > 0)
189
      {
190
         System.arraycopy(b, off, buffer, 0, Math.min(remaining, WRITE_CHUNK_SIZE));
191
         // write at most WRITE_CHUNK_SIZE of data and at most the remaining bytes
192
         out.write(buffer, 0, Math.min(remaining, WRITE_CHUNK_SIZE));
193
         remaining -= buffer.length;
194
         off += buffer.length;
195
      }
158 196
   }
159 197
   
160 198
   /**
......
170 208
      }
171 209
   }
172 210

  
211
   /**
212
    * Flushes the underlying stream.
213
    */
173 214
   @Override
174 215
   public void flush() throws IOException
175 216
   {
new/src/com/goldencode/p2j/util/TargetLobFile.java 2022-06-09 16:22:23 +0000
10 10
** 003 OM  20210328 Improved COPY-LOB engine and validations.
11 11
**     OM  20210404 Used a getter to expose the file name.
12 12
**     EVL 20220406 Catching more exceptions to inform the target file is missing or invalid.
13
**     TJD 20220607 Switch to OutputStreamWriter to allow chunked write
13 14
*/
14 15

  
15 16
/*
......
136 137
   @Override
137 138
   public void write(byte[] data)
138 139
   {
139
      Stream stream = null;
140
      try
141
      {
142
         stream = StreamFactory.openFileStream(filename, true, append);
143
      }
144
      catch (DeferredLegacyErrorException dlee)
145
      {
146
         ErrorManager.recordOrThrowError(43, filename, "3");
147
         // ** Cannot find or open file <file-name>, errno = <number>. (43)
148
         return;
149
      }
150
      catch (ErrorConditionException ece)
151
      {
152
         ErrorManager.recordOrThrowError(43, filename, "3");
153
         // ** Cannot find or open file <file-name>, errno = <number>. (43)
154
         return;
155
      }
156
      
157 140
      if (data == null)
158 141
      {
159 142
         // if the source is unknown (so the [data] is null) the file will still be created but empty 
160 143
         data = new byte[0];
161 144
      }
162
      
163
      try
164
      {
165
         stream.write(data);
145
      Stream stream = openStream();
146
      if (stream == null)
147
      {
148
         return;
149
      }
150
      // underlying stream will be closed by wrapper at the end of write
151
      try (OutputStreamWrapper os = new OutputStreamWrapper(stream))
152
      {
153
         os.write(data);
166 154
      }
167 155
      catch (IOException exc)
168 156
      {
169 157
         ErrorManager.recordOrThrowError(43, filename, "13");
170 158
         // ** Cannot find or open file <file-name>, errno = <number>. (43)
171 159
      }
172
      finally
173
      {
174
         stream.close();
175
      }
160

  
176 161
   }
177 162
   
178 163
   /**
......
208 193
         }
209 194
      }
210 195
      
211
      Stream stream = StreamFactory.openFileStream(filename, true, append);
212
      
213
      try
196
      Stream stream = openStream();
197
      if (stream == null)
198
      {
199
         return;
200
      }
201
      // underlying stream will be closed by wrapper at the end of write
202
      try (OutputStreamWrapper os = new OutputStreamWrapper(stream))
214 203
      {
215 204
         stream.write(data.getBytes(javaCS));
216 205
      }
......
219 208
         ErrorManager.recordOrThrowError(43, filename, "13");
220 209
         // ** Cannot find or open file <file-name>, errno = <number>. (43)
221 210
      }
222
      finally
223
      {
224
         stream.close();
225
      }
226 211
   }
227 212
   
228 213
   /**
......
255 240
      
256 241
      return filename.toStringMessage();
257 242
   }
243
   
244
   /**
245
    * Open stream using StreamFactory for writing, optionally in append mode 
246
    * @return Stream object instance or null in case of failure
247
    */
248
   private Stream openStream()
249
   {
250
      /** File stream for output file, which is a remote resource */
251
      Stream stream = null;
252
      
253
      try
254
      {
255
         stream = StreamFactory.openFileStream(filename, true, append);
256
      }
257
      catch (DeferredLegacyErrorException dlee)
258
      {
259
         ErrorManager.recordOrThrowError(43, filename, "2");
260
         // ** Cannot find or open file <file-name>, errno = <number>. (43)
261
      }
262
      catch (ErrorConditionException ece)
263
      {
264
         ErrorManager.recordOrThrowError(43, filename, "3");
265
         // ** Cannot find or open file <file-name>, errno = <number>. (43)
266
      }
267
      return stream;
268
   }
258 269
}