Thursday 4 December 2014

Do things in the right place and at the right time

Suppose you have just 25% fuel and want to go to a city which you just know it takes an hour or two of driving from your home. You know there is two gas stations on the road, one near your city and the other near the target city. In which one of them are you going to stop and fill up the tank?

You probably go for the nearest gas station then drive calm toward the destination. Even if something unusual happens you still have another gas station in the road. This is what we usually do. But why we don't do the same when we write code, design algorithms or software?

How many times have you experienced the "not enough free disk space", "disk full", ... after a while the operating system starts to copy files! I always wonder why some operating systems don't check the size of the file or files being copied to the target disk and the required free space before starting the copy process.



Have you ever gotten out of disk space on MySQL server? Does it say or log "out of disk space", no it just starts to behave abnormally. Although some may say it is not MySQL's job to make sure there is always some amount of free disk space or any other resources (the worse problem happens when it gets out of memory), I don't remember who said software should always assume they have all required resources to work? Especially for those who should work for years without any interruption.

Check for resources you need before using them 
Yes, some say this is a pattern, I think it does have a name too, but I don't like patterns, they are good but all of them must be in your blood and thought regardless of what other people name them. The following pseudo code is a good way to control the file copy.

sourceSize := calculateFileListSize(fileList);
destinationFreeSize := getDestinationFreeSize(); // it will return the free size the user can use ...
if (sourceSize < destinationFreeSize) {
  fileList.goBeforeFirst();
  do {
    file := fileList.next();
    copyFile(file);
  }  while (file != null);
} else {
  throwException(NOT_ENOUGH_DISK_SPACE);
}

It is not bad it works, at least, it allows you to find out if the target doesn't have space for the whole selected files or not at first. Then you have the choice of re-selecting the source files. But let us be more accurate, our copy application will not be the only who uses the disk, so let us do it like the following:

do {
  sourceSize := calculateFileListSize(fileList);
  destinationFreeSize := getDestinationFreeSize();
  if (sourceSize < destinationFreeSize) {
    file := fileList.getFirst();
    copyFile(file);
    fileList.removeFirst();
  } else {
     throwException(NOT_ENOUGH_DISK_SPACE);
  }
}  while (file != null);

In this form, we always make sure at the time we want to copy, that we have enough space for the rest of the uncopied files. This is perhaps something like what most operating system does but still has a problem because we have seen some operating system give you copy error message after copying some portion of a single too.

Lock/Allocate resources you need before using them 
How can we make sure the copy we are going to do will completely be done? Easy, exactly like what many torrent application do, they allocate required disk space at first and then use that space for downloading files. If I'm not mistaken when you create a tablespace in oracle, it does the same. So the following code works safer:

sourceSize := calculateFileListSize(fileList);
destinationFreeSize := getDestinationFreeSize();
if (sourceSize < destinationFreeSize) {
  destinationTempSpace = allocateDestinationDiskSpace(destinationFreeSize);
  if (destinationTempSpace != 0) {
    fileList.goBeforeFirst();
    do {
      file = fileList.next();
      copyFile(file, destinationTempSpace);
    }  while (file != null);
  } else {
    throwException(CAN_NOT_ALLOCATE_DISK_SPACE);
  }
} else {
  throwException(NOT_ENOUGH_DISK_SPACE);
}

The same idea is true for any resources you want to use, memory, TCP socket, ... allocate them at the start of the process or you may need to return some of them if the process gets into allocation trouble. You know better than me how difficult is existing and deallocating from deep and inner part of a complex process.

No comments:

Post a Comment