0

i need to achieve the task as below:-

1). File upload on primary location:-

I want to read from a file and write it to primary location(remote file server).

2). File upload on multiple secondary locations:-

Same time while writing to primary location is running, parallelly I want to read some chunks of bytes from primary location file and writing it to multiple secondary location.

I have tried a below program for above approach:-

BufferedInputStream bin = null;
        ReadableByteChannel channel = null;
        int bufferSize = 1048576;
        int readBufferSize = 1024*4;
        java.nio.ByteBuffer byteBuffer = java.nio.ByteBuffer.allocate(readBufferSize);
        InputStream is = new FileInputStream(new File("D:\\Harisingh\\300MB.txt"));

        bin = new BufferedInputStream(is,bufferSize);
        channel = Channels.newChannel(bin);
        int retryCnt = 0;
        ByteArrayOutputStream baOS = new ByteArrayOutputStream(bufferSize);
        int totalBytes=0;
        int itrCount=0;
        int maxIterateCnt = 1;
        int len;
        //primary location writing
        SmbFile smbFile = new SmbFile("smb://user:Password@fileserver1ind1.hqdev.india/data/Harisingh/collab_4_1_4/primary.txt");
        BufferedOutputStream bFout = new BufferedOutputStream(new SmbFileOutputStream(smbFile));

        SmbFileInputStream fis = new SmbFileInputStream("smb://user:Password@fileserver1ind1.hqdev.india/data/Harisingh/collab_4_1_4/primary.txt");
        BufferedInputStream binPrimary = new BufferedInputStream(fis);

        SmbFileOutputStream secLocation1= new SmbFileOutputStream(new SmbFile("smb://user:Password@fileserver1ind1.hqdev.india/data/Harisingh/collab_4_1_4/Secondary1.txt"));
        SmbFileOutputStream secLocation2 = new SmbFileOutputStream(new SmbFile("smb://user:Password@fileserver1ind1.hqdev.india/data/Harisingh/collab_4_1_4/Secondary2.txt"));
        SmbFileOutputStream secLocation3 = new SmbFileOutputStream(new SmbFile("smb://user:Password@fileserver1ind1.hqdev.india/data/Harisingh/Secondary/Secondary3.txt"));
        try {
            if(bufferSize > readBufferSize){
                maxIterateCnt = bufferSize/readBufferSize;
            }
            while((len=channel.read(byteBuffer))>=0) 
            {
                itrCount++;
                totalBytes+=len;
                baOS.write(byteBuffer.array(),0,len);
                if(itrCount>=maxIterateCnt)
                {
                    //primary location writing
                    try{
                        bFout.write(baOS.toByteArray(),0,totalBytes);
                    }catch(Exception se)
                    {
                    }

                    // secondary location writing
                    new Thread(){
                           public void run(){
                              System.out.println("Thread Running");
                              try {
                                int count;
                                byte[] readByteArray = new byte[1024*4];
                                while ((count = binPrimary.read(readByteArray)) != -1)
                                    {
                                        secLocation1.write(readByteArray, 0, count);
                                        secLocation2.write(readByteArray, 0, count);
                                        secLocation3.write(readByteArray, 0, count);
                                        readByteArray = new byte[1024*4];
                                        count= 0;
                                    }
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                          }
                      }.start();
                    totalBytes=0;
                    baOS.reset();
                    itrCount=0;
                }
                byteBuffer.clear();
            }

            //primary location writing
            try{
                bFout.write(baOS.toByteArray(),0,totalBytes);
            }catch(Exception se)
            {
            }
            bFout.flush();
            bFout.close();
            int count;
            // secondary location writing
            new Thread(){
                public void run(){
                  System.out.println("Thread Running");
                  try {
                    int count;
                    byte[] readByteArray = new byte[1024*4];
                    while ((count = binPrimary.read(readByteArray)) != -1)
                    {
                            secLocation1.write(readByteArray, 0, count);
                            secLocation2.write(readByteArray, 0, count);
                            secLocation3.write(readByteArray, 0, count);
                            readByteArray = new byte[1024*4];
                            count= 0;
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                }
              }.start();

Now with above program, it writes a file to primary location by main thread and secondary location writing is running in separate thread but i am facing the problem of some bytes writing missing on some secondary locations due to multi threading.

FYI

This question is related to io stream only. It is not specific to JCIFS so you can use same program with simple io stream, don't require smb io stream. Can you please help me to sort out this?

  • Have you tried to treat your secondary locations as primary one? I mean wrap SmbFileOutputStream into BufferedOutputStream for secLocation1, secLocation2 and secLocation3 and do not forget to flush – VitalyZ May 01 '18 at 14:12
  • @VitalyZ Thanks for your quick response. It works fine now with wrapping SmbFileOutputStream into BufferedOutputStream. – Harisingh Rajput May 02 '18 at 06:47
  • @VitalyZ As per previous comment, it worked fine by with wrapping SmbFileOutputStream into BufferedOutputStream and flushing but now came to know that file size seems same for all secondary locations but file content is different and its not proper. I have compared MD5 of secondary files but it looks different for all. So can you please help me into this why file size is same but file content is different. It seems that still something going wrong in file writing. – Harisingh Rajput May 02 '18 at 12:46
  • Every time you write to primary you create a thread which will write all secondary files all over again from start? I think you should keep track how many bytes have been written to primary, how many have you read from primary for secondaries and play with reading the offset. Also I don't know if there is any real benefit for doing the secondary writing in parallel threads, only confuses the handling. 1. Read File, 2. WritePR, 3. Flush, 4. ReadPR, 5. WriteSEC, 6. WriteSEC, 7. WriteSEC, 8. Flush, 9. Repeat – Jokkeri May 03 '18 at 12:35
  • @Jokkeri Actually i don't have control of thread to read bytes in sequence exactly written to primary file. Do you have any idea about how can i track it and write it sequentially in secondary file so file content can be proper? Or what do you suggest? Should i read primary file after it completely be written? or can i read it while writing is going on? – Harisingh Rajput May 03 '18 at 13:19
  • @HarisinghRajput Depends on what is the main goal. Is it just to get the files copied or is it to get the files copied with the most efficient way... The easiest way is to fully copy the primary file first and then copy it to secondary locations. Question; what is the reason there is a "primary" location? Couldn't you just copy the original file into 4 equal locations? – Jokkeri May 04 '18 at 05:19
  • @Jokkeri Yes now we are trying with the easiest way is to fully copy the primary file first and then copy it to secondary locations which is straight forward way.and its working fine. **Couldn't you just copy the original file into 4 equal locations?** If we go with this approach, then it degrades our performance because of we should wait till 4 locations writing completes. Our purpose of primary location is that first we should wait for only primary location upload and secondary locations writing should be run asynchronously in background so we gives that process to threading – Harisingh Rajput May 04 '18 at 06:11
  • @Jokkeri As soon as primary location file upload completes, we will give success response regardless of secondary locations file upload completes or pending. I think now it is more clear to you – Harisingh Rajput May 04 '18 at 06:12

1 Answers1

1

Here is an example which I do not encourage to use "as is" - it's intention is to act as Proof Of Concept. In example the primary process is done first to achieve best performance for this phase. Then the secondaries are done each in own Thread parallel.

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.UnknownHostException;

import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;

public class testSmb {

    static boolean append = true;
    static int threadCount = 0;

    static int bufferSize = 2048;

    static NtlmPasswordAuthentication auth;

    static File localFile;

    static SmbFile primarySmbFile;
    static BufferedInputStream input;
    static SmbFileOutputStream output;

    static SmbFile secondary1SmbFile;
    static BufferedInputStream sec1Input;
    static SmbFileOutputStream sec1Output;

    static SmbFile secondary2SmbFile;
    static BufferedInputStream sec2Input;
    static SmbFileOutputStream sec2Output;

    static SmbFile secondary3SmbFile;
    static BufferedInputStream sec3Input;
    static SmbFileOutputStream sec3Output;

    public static Object lock = new Object();

    public static void main(String... args) throws IOException {
        System.out.println("Main thread Started");
        init();
        write(input, output);
        writeInThread(sec1Input, sec1Output);
        writeInThread(sec2Input, sec2Output);
        writeInThread(sec3Input, sec3Output);

        System.out.println("Main thread Finished");
    }

    public static void init() throws MalformedURLException,
            FileNotFoundException, SmbException, UnknownHostException {

        localFile = new File("c:\\temp\\myFile.txt");
        if (localFile.length() > 20971520l) {
            bufferSize = 131072;
        }

        String server = "myServer";
        String username = "myUser";
        String password = "myPass";
        String path = "myPath";
        auth = new NtlmPasswordAuthentication(server, username, password);

        input = new BufferedInputStream(new FileInputStream(localFile));
        primarySmbFile = new SmbFile("smb://" + server + "/" + path
                + "/primary.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        output = new SmbFileOutputStream(primarySmbFile, append);
        if (!primarySmbFile.exists()) {
            primarySmbFile.createNewFile();
        }

        sec1Input = new BufferedInputStream(new SmbFileInputStream(new SmbFile(
                primarySmbFile, primarySmbFile.getName())));
        secondary1SmbFile = new SmbFile("smb://" + server + "/" + path
                + "/secondary1.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        sec1Output = new SmbFileOutputStream(secondary1SmbFile, append);
        if (!secondary1SmbFile.exists()) {
            secondary1SmbFile.createNewFile();
        }

        sec2Input = new BufferedInputStream(new SmbFileInputStream(new SmbFile(
                primarySmbFile, primarySmbFile.getName())));
        secondary2SmbFile = new SmbFile("smb://" + server + "/" + path
                + "/secondary2.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        sec2Output = new SmbFileOutputStream(secondary2SmbFile, append);
        if (!secondary2SmbFile.exists()) {
            secondary2SmbFile.createNewFile();
        }

        sec3Input = new BufferedInputStream(new SmbFileInputStream(new SmbFile(
                primarySmbFile, primarySmbFile.getName())));
        secondary3SmbFile = new SmbFile("smb://" + server + "/" + path
                + "/secondary3.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        sec3Output = new SmbFileOutputStream(secondary3SmbFile, append);
        if (!secondary3SmbFile.exists()) {
            secondary3SmbFile.createNewFile();
        }

    }

    public static void write(BufferedInputStream bufferedInputStream,
            SmbFileOutputStream smbFileOutputStream) throws IOException {

        byte[] buffer = new byte[bufferSize];
        int len = 0;

        try {

            while ((len = bufferedInputStream.read(buffer)) > 0) {
                synchronized (lock) {
                    System.out.println("'" + Thread.currentThread().getName()
                            + "' writing " + bufferSize + "bytes");
                    smbFileOutputStream.write(buffer, 0, len);
                    smbFileOutputStream.flush();
                }
            }

        } catch (IOException e) {
            throw e;
        } finally {
            try {
                bufferedInputStream.close();
            } catch (Exception e) {
            }

            try {
                smbFileOutputStream.flush();
                smbFileOutputStream.close();
            } catch (Exception e) {
            }
        }

    }

    public static void writeInThread(
            final BufferedInputStream bufferedInputStream,
            final SmbFileOutputStream smbFileOutputStream) {
        threadCount++;

        new Thread("Secondary thread " + threadCount) {
            public void run() {
                System.out.println(Thread.currentThread().getName()
                        + ": started");
                try {
                    write(bufferedInputStream, smbFileOutputStream);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + ": finished");
            }
        }.start();

    }
}
Jokkeri
  • 1,001
  • 1
  • 13
  • 35
  • Thanks for sharing the program. It is working fine as we have discussed that it start to upload file on secondary locations after primary file upload completes. Now i have a question that all secondary locations writing in parallelly or one by one in sequentially? – Harisingh Rajput May 04 '18 at 10:31
  • Thanks a lot for sharing the program. We did the same as i have commented earlier **we are trying with the easiest way is to fully copy the primary file first and then copy it to secondary locations which is straight forward way** We dont have a problem with this approach. We faced issue only with same time reading and writing to primary file approach – Harisingh Rajput May 04 '18 at 10:38
  • Edited the example to make it parallel – Jokkeri May 04 '18 at 10:48
  • jcifs.smb.SmbException: The handle is invalid. – Harisingh Rajput May 04 '18 at 11:35
  • **In parallel writing, sometimes it get success and sometimes it gives below error in case of large file size approax 200MB** at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:563) at jcifs.smb.SmbTransport.send(SmbTransport.java:663) at jcifs.smb.SmbSession.send(SmbSession.java:238) at jcifs.smb.SmbTree.send(SmbTree.java:119) at jcifs.smb.SmbFile.send(SmbFile.java:775) at jcifs.smb.SmbFileInputStream.readDirect(SmbFileInputStream.java:181) – Harisingh Rajput May 04 '18 at 11:37
  • @HarisinghRajput How about now (edited the example), added some synchronization and did not reuse the primarySmbFile Object when creating inputStream – Jokkeri May 04 '18 at 12:23
  • After adding synchronization, it is working fine now. I appreciate your help.Thank you so much for your continual support. – Harisingh Rajput May 04 '18 at 14:06
  • Good to hear, if the answer resolves your problem please accept it – Jokkeri May 07 '18 at 04:38
  • Actually i have raised this question for as per mentioned in title **File upload on primary location and same time reading & writing same file to multiple secondary locations** Its for problem with same time reading and writing to a primary file. And we have tried different approach of first fully upload on primary and then copy it to secondary locations which is sequential approach. So i think that your answer gives me other approach but not a related to asked question. – Harisingh Rajput May 07 '18 at 05:39
  • I appreciate all your help. But it would be good, if you can mention here that same time reading/writing is not possible and i should follow sequential approach(e.g. First primary file fully upload then only read from primary and write to multiple secondary files). What do you say? – Harisingh Rajput May 07 '18 at 05:43
  • its very slow.. can we make faster? I have updated buffersize but still its slow only – Vijaysinh Parmar Nov 11 '20 at 12:38
  • Try this https://stackoverflow.com/questions/10533653/jcifs-file-retrieval-is-too-slow-to-be-usable. Particularly the `jcifs.resolveOrder` and `jcifs.smb.client.dfs.disabled` properties. Programmatically you can use those like this `jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");` – Jokkeri Nov 13 '20 at 12:51